mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-19 11:14:41 +00:00
Partially implement (FPP)^2
This commit is contained in:
parent
0e94b931a2
commit
f7a5748fd3
@ -520,7 +520,7 @@ class bigint {
|
|||||||
// Computes *this -= other assuming aligned bigints and *this >= other.
|
// Computes *this -= other assuming aligned bigints and *this >= other.
|
||||||
void subtract_aligned(const bigint& other) {
|
void subtract_aligned(const bigint& other) {
|
||||||
FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints");
|
FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints");
|
||||||
FMT_ASSERT(*this >= other, "");
|
FMT_ASSERT(compare(*this, other) >= 0, "");
|
||||||
bigit borrow = 0;
|
bigit borrow = 0;
|
||||||
int i = other.exp_ - exp_;
|
int i = other.exp_ - exp_;
|
||||||
for (int j = 0, n = static_cast<int>(other.bigits_.size()); j != n;
|
for (int j = 0, n = static_cast<int>(other.bigits_.size()); j != n;
|
||||||
@ -530,22 +530,6 @@ 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 i = static_cast<int>(lhs.bigits_.size()) - 1;
|
|
||||||
int j = static_cast<int>(rhs.bigits_.size()) - 1;
|
|
||||||
int end = i - j;
|
|
||||||
if (end < 0) end = 0;
|
|
||||||
for (; i >= end; --i, --j) {
|
|
||||||
bigit lhs_bigit = lhs.bigits_[i], rhs_bigit = rhs.bigits_[j];
|
|
||||||
if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1;
|
|
||||||
}
|
|
||||||
if (i != j) return i > j ? 1 : -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bigint() : exp_(0) {}
|
bigint() : exp_(0) {}
|
||||||
|
|
||||||
@ -590,17 +574,20 @@ class bigint {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator<(const bigint& lhs, const bigint& rhs) {
|
friend int compare(const bigint& lhs, const bigint& rhs) {
|
||||||
return compare(lhs, rhs) < 0;
|
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 i = static_cast<int>(lhs.bigits_.size()) - 1;
|
||||||
|
int j = static_cast<int>(rhs.bigits_.size()) - 1;
|
||||||
|
int end = i - j;
|
||||||
|
if (end < 0) end = 0;
|
||||||
|
for (; i >= end; --i, --j) {
|
||||||
|
bigit lhs_bigit = lhs.bigits_[i], rhs_bigit = rhs.bigits_[j];
|
||||||
|
if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1;
|
||||||
}
|
}
|
||||||
friend bool operator>(const bigint& lhs, const bigint& rhs) {
|
if (i != j) return i > j ? 1 : -1;
|
||||||
return compare(lhs, rhs) > 0;
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns compare(lhs1 + lhs2, rhs).
|
// Returns compare(lhs1 + lhs2, rhs).
|
||||||
@ -684,7 +671,7 @@ class bigint {
|
|||||||
// returning the quotient.
|
// returning the quotient.
|
||||||
int divmod_assign(const bigint& divisor) {
|
int divmod_assign(const bigint& divisor) {
|
||||||
FMT_ASSERT(this != &divisor, "");
|
FMT_ASSERT(this != &divisor, "");
|
||||||
if (!(*this >= divisor)) return 0;
|
if (compare(*this, divisor) < 0) return 0;
|
||||||
int num_bigits = static_cast<int>(bigits_.size());
|
int num_bigits = static_cast<int>(bigits_.size());
|
||||||
FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1] != 0, "");
|
FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1] != 0, "");
|
||||||
int exp_difference = exp_ - divisor.exp_;
|
int exp_difference = exp_ - divisor.exp_;
|
||||||
@ -700,7 +687,7 @@ class bigint {
|
|||||||
do {
|
do {
|
||||||
subtract_aligned(divisor);
|
subtract_aligned(divisor);
|
||||||
++quotient;
|
++quotient;
|
||||||
} while (*this >= divisor);
|
} while (compare(*this, divisor) >= 0);
|
||||||
return quotient;
|
return quotient;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -921,7 +908,8 @@ 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:
|
||||||
|
// http://kurtstephens.com/files/p372-steele.pdf.
|
||||||
template <typename Double>
|
template <typename Double>
|
||||||
FMT_FUNC void fallback_format(Double v, buffer<char>& buf, int& exp10) {
|
FMT_FUNC void fallback_format(Double v, buffer<char>& buf, int& exp10) {
|
||||||
fp fp_value(v);
|
fp fp_value(v);
|
||||||
@ -929,43 +917,44 @@ FMT_FUNC void fallback_format(Double v, buffer<char>& buf, int& exp10) {
|
|||||||
// TODO: handle denormals
|
// TODO: handle denormals
|
||||||
int shift = fp_value.f == 1 ? 1 : 0;
|
int shift = fp_value.f == 1 ? 1 : 0;
|
||||||
// Shift value and pow10 by an extra bit to make lower and upper which are
|
// Shift value and pow10 by an extra bit to make lower and upper which are
|
||||||
// half ulp integers. This eliminates multiplication by 2 during later
|
// normally half ulp integers. This eliminates multiplication by 2 during
|
||||||
// computations.
|
// later computations.
|
||||||
bigint value(fp_value.f << (shift + 1)); // 2 * R in (FPP)^2.
|
bigint value(fp_value.f << (shift + 1)); // 2 * R in (FPP)^2.
|
||||||
bigint pow10(1 << (shift + 1)); // 2 * S in (FPP)^2.
|
bigint pow10; // 2 * S in (FPP)^2.
|
||||||
bigint lower(1); // M^- in (FPP)^2.
|
bigint lower(1); // (M^- in (FPP)^2).
|
||||||
bigint upper(1 << shift); // M^+ in (FPP)^2.
|
bigint upper(1 << shift); // (M^+ in (FPP)^2).
|
||||||
if (fp_value.e >= 0) {
|
if (fp_value.e >= 0) {
|
||||||
value <<= fp_value.e;
|
value <<= fp_value.e;
|
||||||
lower <<= fp_value.e;
|
lower <<= fp_value.e;
|
||||||
upper <<= fp_value.e;
|
upper <<= fp_value.e;
|
||||||
|
pow10.assign_pow10(exp10);
|
||||||
|
pow10 <<= 1;
|
||||||
} else {
|
} else {
|
||||||
pow10 <<= -fp_value.e;
|
pow10 <<= -fp_value.e;
|
||||||
// TODO: fixup
|
// TODO: fixup
|
||||||
}
|
}
|
||||||
// fp_value == value / pow10.
|
// Invariant: fp_value == (value / pow10) * pow(10, exp10).
|
||||||
int exp = 0;
|
bool even = (fp_value.f & 1) == 0;
|
||||||
while (add_compare(value, upper, pow10) >= 0) {
|
|
||||||
pow10 *= 10;
|
|
||||||
++exp;
|
|
||||||
}
|
|
||||||
int num_digits = 0;
|
int num_digits = 0;
|
||||||
char* data = buf.data();
|
char* data = buf.data();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
value *= 10;
|
|
||||||
int digit = value.divmod_assign(pow10);
|
int digit = value.divmod_assign(pow10);
|
||||||
lower *= 10;
|
bool low = compare(value, lower) - even < 0; // value <[=] lower.
|
||||||
upper *= 10;
|
bool high = add_compare(value, upper, pow10) + even >
|
||||||
bool low = value < lower;
|
0; // value + upper >[=] pow10.
|
||||||
bool high = add_compare(value, upper, pow10) > 0; // value + upper > pow10
|
|
||||||
if (low || high) {
|
if (low || high) {
|
||||||
if (!low) ++digit;
|
if (!low) {
|
||||||
|
++digit;
|
||||||
|
} else if (high) {
|
||||||
|
// TODO: round up if 2 * value >= pow10
|
||||||
|
}
|
||||||
data[num_digits++] = static_cast<char>('0' + digit);
|
data[num_digits++] = static_cast<char>('0' + digit);
|
||||||
buf.resize(num_digits);
|
buf.resize(num_digits);
|
||||||
exp10 = exp - num_digits;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data[num_digits++] = static_cast<char>('0' + digit);
|
data[num_digits++] = static_cast<char>('0' + digit);
|
||||||
|
lower *= 10;
|
||||||
|
upper *= 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,64 +35,18 @@ TEST(BigIntTest, Construct) {
|
|||||||
EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
|
EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BigIntTest, Less) {
|
TEST(BigIntTest, Compare) {
|
||||||
bigint n1(42);
|
bigint n1(42);
|
||||||
bigint n2(42);
|
bigint n2(42);
|
||||||
EXPECT_FALSE(n1 < n2);
|
EXPECT_EQ(compare(n1, n2), 0);
|
||||||
n2 <<= 32;
|
n2 <<= 32;
|
||||||
EXPECT_TRUE(n1 < n2);
|
EXPECT_LT(compare(n1, n2), 0);
|
||||||
EXPECT_FALSE(n2 < n1);
|
|
||||||
bigint n3(43);
|
bigint n3(43);
|
||||||
EXPECT_TRUE(n1 < n3);
|
EXPECT_LT(compare(n1, n3), 0);
|
||||||
EXPECT_FALSE(n3 < n1);
|
EXPECT_GT(compare(n3, n1), 0);
|
||||||
bigint n4(42 * 0x100000001);
|
bigint n4(42 * 0x100000001);
|
||||||
EXPECT_TRUE(n2 < n4);
|
EXPECT_LT(compare(n2, n4), 0);
|
||||||
EXPECT_FALSE(n4 < n2);
|
EXPECT_GT(compare(n4, n2), 0);
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
bigint n1(42);
|
|
||||||
bigint n2(42);
|
|
||||||
EXPECT_TRUE(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, AddCompare) {
|
TEST(BigIntTest, AddCompare) {
|
||||||
|
Loading…
Reference in New Issue
Block a user