mirror of
https://github.com/fmtlib/fmt.git
synced 2024-10-02 04:52:03 +00:00
Implement more comparison operators
This commit is contained in:
parent
96f91428c6
commit
b55551f900
@ -530,6 +530,24 @@ class bigint {
|
|||||||
while (borrow > 0) subtract_bigits(i, 0, borrow);
|
while (borrow > 0) subtract_bigits(i, 0, borrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend int compare(const bigint& lhs, const bigint& rhs) {
|
||||||
|
int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits();
|
||||||
|
if (num_lhs_bigits != num_rhs_bigits)
|
||||||
|
return num_lhs_bigits > num_rhs_bigits ? 1 : -1;
|
||||||
|
int lhs_bigit_index = static_cast<int>(lhs.bigits_.size()) - 1;
|
||||||
|
int rhs_bigit_index = static_cast<int>(rhs.bigits_.size()) - 1;
|
||||||
|
int end = lhs_bigit_index - rhs_bigit_index;
|
||||||
|
if (end < 0) end = 0;
|
||||||
|
for (; lhs_bigit_index >= end; --lhs_bigit_index, --rhs_bigit_index) {
|
||||||
|
bigit lhs_bigit = lhs.bigits_[lhs_bigit_index];
|
||||||
|
bigit rhs_bigit = rhs.bigits_[rhs_bigit_index];
|
||||||
|
if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1;
|
||||||
|
}
|
||||||
|
if (lhs_bigit_index != rhs_bigit_index)
|
||||||
|
return lhs_bigit_index > rhs_bigit_index ? 1 : -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bigint() : exp_(0) {}
|
bigint() : exp_(0) {}
|
||||||
|
|
||||||
@ -574,20 +592,17 @@ class bigint {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator>=(const bigint& lhs, const bigint& rhs) {
|
friend bool operator<(const bigint& lhs, const bigint& rhs) {
|
||||||
int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits();
|
return compare(lhs, rhs) < 0;
|
||||||
if (num_lhs_bigits != num_rhs_bigits)
|
|
||||||
return num_lhs_bigits > num_rhs_bigits;
|
|
||||||
int lhs_bigit_index = static_cast<int>(lhs.bigits_.size()) - 1;
|
|
||||||
int rhs_bigit_index = static_cast<int>(rhs.bigits_.size()) - 1;
|
|
||||||
int end = lhs_bigit_index - rhs_bigit_index;
|
|
||||||
if (end < 0) end = 0;
|
|
||||||
for (; lhs_bigit_index >= end; --lhs_bigit_index, --rhs_bigit_index) {
|
|
||||||
bigit lhs_bigit = lhs.bigits_[lhs_bigit_index];
|
|
||||||
bigit rhs_bigit = rhs.bigits_[rhs_bigit_index];
|
|
||||||
if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit;
|
|
||||||
}
|
}
|
||||||
return lhs_bigit_index >= rhs_bigit_index;
|
friend bool operator>(const bigint& lhs, const bigint& rhs) {
|
||||||
|
return compare(lhs, rhs) > 0;
|
||||||
|
}
|
||||||
|
friend bool operator<=(const bigint& lhs, const bigint& rhs) {
|
||||||
|
return compare(lhs, rhs) <= 0;
|
||||||
|
}
|
||||||
|
friend bool operator>=(const bigint& lhs, const bigint& rhs) {
|
||||||
|
return compare(lhs, rhs) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assigns pow(10, exp) to this bigint.
|
// Assigns pow(10, exp) to this bigint.
|
||||||
@ -721,44 +736,39 @@ digits::result grisu_gen_digits(fp value, uint64_t error, int& exp,
|
|||||||
// Generate digits for the integral part. This can produce up to 10 digits.
|
// Generate digits for the integral part. This can produce up to 10 digits.
|
||||||
do {
|
do {
|
||||||
uint32_t digit = 0;
|
uint32_t digit = 0;
|
||||||
|
auto divmod_integral = [&](uint32_t divisor) {
|
||||||
|
digit = integral / divisor;
|
||||||
|
integral %= divisor;
|
||||||
|
};
|
||||||
// This optimization by miloyip reduces the number of integer divisions by
|
// This optimization by miloyip reduces the number of integer divisions by
|
||||||
// one per iteration.
|
// one per iteration.
|
||||||
switch (exp) {
|
switch (exp) {
|
||||||
case 10:
|
case 10:
|
||||||
digit = integral / 1000000000;
|
divmod_integral(1000000000);
|
||||||
integral %= 1000000000;
|
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
digit = integral / 100000000;
|
divmod_integral(100000000);
|
||||||
integral %= 100000000;
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
digit = integral / 10000000;
|
divmod_integral(10000000);
|
||||||
integral %= 10000000;
|
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
digit = integral / 1000000;
|
divmod_integral(1000000);
|
||||||
integral %= 1000000;
|
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
digit = integral / 100000;
|
divmod_integral(100000);
|
||||||
integral %= 100000;
|
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
digit = integral / 10000;
|
divmod_integral(10000);
|
||||||
integral %= 10000;
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
digit = integral / 1000;
|
divmod_integral(1000);
|
||||||
integral %= 1000;
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
digit = integral / 100;
|
divmod_integral(100);
|
||||||
integral %= 100;
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
digit = integral / 10;
|
divmod_integral(10);
|
||||||
integral %= 10;
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
digit = integral;
|
digit = integral;
|
||||||
@ -890,23 +900,36 @@ template <int GRISU_VERSION> struct grisu_shortest_handler {
|
|||||||
|
|
||||||
// Format value using a variation of the Fixed-Precision Positive Floating-Point
|
// Format value using a variation of the Fixed-Precision Positive Floating-Point
|
||||||
// Printout ((FPP)^2) algorithm by Steele & White.
|
// Printout ((FPP)^2) algorithm by Steele & White.
|
||||||
FMT_FUNC void fallback_format(const fp& value, int exp10) {
|
template <typename Double> FMT_FUNC void fallback_format(Double v, int exp10) {
|
||||||
bigint big_value(value.f); // R in (FPP)^2.
|
(void)exp10;
|
||||||
bigint pow10; // S in (FPP)^2.
|
fp fp_value(v);
|
||||||
bigint lower(uint32_t(1)); // M^- in (FPP)^2.
|
// Shift to account for unequal gaps when lower boundary is 2 times closer.
|
||||||
bigint upper(uint32_t(1)); // M^+ in (FPP)^2.
|
// TODO: handle denormals
|
||||||
if (value.e >= 0) {
|
int shift = fp_value.f == 1 ? 1 : 0;
|
||||||
big_value <<= value.e + 1;
|
// Shift value and pow10 by an extra bit to make lower and upper which are
|
||||||
pow10.assign_pow10(exp10);
|
// half ulp integers. This eliminates multiplication by 2 during later
|
||||||
pow10 <<= 1;
|
// computations in (FPP)^2.
|
||||||
lower <<= value.e;
|
bigint value(fp_value.f << (shift + 1)); // R in (FPP)^2.
|
||||||
upper <<= value.e;
|
bigint pow10(1 << (shift + 1)); // S in (FPP)^2.
|
||||||
|
bigint lower(1); // M^- in (FPP)^2.
|
||||||
|
bigint upper(1 << shift); // M^+ in (FPP)^2.
|
||||||
|
if (fp_value.e >= 0) {
|
||||||
|
value <<= fp_value.e;
|
||||||
|
lower <<= fp_value.e;
|
||||||
|
upper <<= fp_value.e;
|
||||||
} else {
|
} else {
|
||||||
// TODO: handle negative exponent
|
pow10 <<= -fp_value.e;
|
||||||
|
// TODO: fixup
|
||||||
}
|
}
|
||||||
// v = (big_value / pow10) * pow(10, exp10).
|
// fp_value = value / pow10.
|
||||||
int digit = big_value.divmod_assign(pow10);
|
while (value /* + upper */ >= pow10) pow10 *= 10;
|
||||||
|
do {
|
||||||
|
value *= 10;
|
||||||
|
int digit = value.divmod_assign(pow10);
|
||||||
(void)digit;
|
(void)digit;
|
||||||
|
lower *= 10;
|
||||||
|
upper *= 10;
|
||||||
|
} while (value >= lower && value <= pow10 /* - upper */);
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -963,7 +986,7 @@ FMT_API bool grisu_format(Double value, buffer<char>& buf, int precision,
|
|||||||
result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler);
|
result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler);
|
||||||
size = handler.size;
|
size = handler.size;
|
||||||
if (result == digits::error) {
|
if (result == digits::error) {
|
||||||
fallback_format(fp_value, exp - cached_exp10);
|
fallback_format(value, exp - cached_exp10);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -35,6 +35,51 @@ TEST(BigIntTest, Construct) {
|
|||||||
EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
|
EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(BigIntTest, Less) {
|
||||||
|
bigint n1(42);
|
||||||
|
bigint n2(42);
|
||||||
|
EXPECT_FALSE(n1 < n2);
|
||||||
|
n2 <<= 32;
|
||||||
|
EXPECT_TRUE(n1 < n2);
|
||||||
|
EXPECT_FALSE(n2 < n1);
|
||||||
|
bigint n3(43);
|
||||||
|
EXPECT_TRUE(n1 < n3);
|
||||||
|
EXPECT_FALSE(n3 < n1);
|
||||||
|
bigint n4(42 * 0x100000001);
|
||||||
|
EXPECT_TRUE(n2 < n4);
|
||||||
|
EXPECT_FALSE(n4 < n2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigIntTest, LessEqual) {
|
||||||
|
bigint n1(42);
|
||||||
|
bigint n2(42);
|
||||||
|
EXPECT_TRUE(n1 <= n2);
|
||||||
|
n2 <<= 32;
|
||||||
|
EXPECT_TRUE(n1 <= n2);
|
||||||
|
EXPECT_FALSE(n2 <= n1);
|
||||||
|
bigint n3(43);
|
||||||
|
EXPECT_TRUE(n1 <= n3);
|
||||||
|
EXPECT_FALSE(n3 <= n1);
|
||||||
|
bigint n4(42 * 0x100000001);
|
||||||
|
EXPECT_TRUE(n2 <= n4);
|
||||||
|
EXPECT_FALSE(n4 <= n2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigIntTest, Greater) {
|
||||||
|
bigint n1(42);
|
||||||
|
bigint n2(42);
|
||||||
|
EXPECT_FALSE(n1 > n2);
|
||||||
|
n2 <<= 32;
|
||||||
|
EXPECT_FALSE(n1 > n2);
|
||||||
|
EXPECT_TRUE(n2 > n1);
|
||||||
|
bigint n3(43);
|
||||||
|
EXPECT_FALSE(n1 > n3);
|
||||||
|
EXPECT_TRUE(n3 > n1);
|
||||||
|
bigint n4(42 * 0x100000001);
|
||||||
|
EXPECT_FALSE(n2 > n4);
|
||||||
|
EXPECT_TRUE(n4 > n2);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(BigIntTest, GreaterEqual) {
|
TEST(BigIntTest, GreaterEqual) {
|
||||||
bigint n1(42);
|
bigint n1(42);
|
||||||
bigint n2(42);
|
bigint n2(42);
|
||||||
|
Loading…
Reference in New Issue
Block a user