diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 36bbcf14..ad113ca7 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -398,13 +398,14 @@ class fp { // Normalizes the value converted from double and multiplied by (1 << SHIFT). template friend fp normalize(fp value) { // Handle subnormals. - const auto shifted_implicit_bit = implicit_bit << SHIFT; + const auto shifted_implicit_bit = fp::implicit_bit << SHIFT; while ((value.f & shifted_implicit_bit) == 0) { value.f <<= 1; --value.e; } // Subtract 1 to account for hidden bit. - const auto offset = significand_size - double_significand_size - SHIFT - 1; + const auto offset = + fp::significand_size - fp::double_significand_size - SHIFT - 1; value.f <<= offset; value.e -= offset; return value; @@ -490,6 +491,18 @@ class bigint { bigint(const bigint&) = delete; void operator=(const bigint&) = delete; + + bigint& operator<<=(int shift) { + assert(shift >= 0 && shift < bigit_bits); + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + bigit c = shift != 0 ? bigits_[i] >> (bigit_bits - shift) : 0; + bigits_[i] = (bigits_[i] << shift) + carry; + carry = c; + } + if (carry != 0) bigits_.push_back(carry); + return *this; + } }; enum round_direction { unknown, up, down }; @@ -712,6 +725,10 @@ template struct grisu_shortest_handler { } }; +FMT_API void fallback_format(const fp& value) { + (void)value; // TODO +} + template > FMT_API bool grisu_format(Double value, buffer& buf, int precision, @@ -765,13 +782,13 @@ FMT_API bool grisu_format(Double value, buffer& buf, int precision, result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler); size = handler.size; if (result == digits::error) { - // TODO: use fallback + fallback_format(fp_value); return false; } } else { ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}. --upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}. - grisu_shortest_handler<2> handler{buf.data(), 0, (upper - fp_value).f}; + grisu_shortest_handler<2> handler{buf.data(), 0, (upper - normalized).f}; result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler); size = handler.size; assert(result != digits::error); diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index f1e407f2..afcc86f8 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -33,6 +33,16 @@ TEST(BigIntTest, Construct) { EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0))); } +TEST(BigIntTest, ShiftLeft) { + bigint n(0x42); + n <<= 0; + EXPECT_EQ("42", fmt::format("{}", n)); + n <<= 1; + EXPECT_EQ("84", fmt::format("{}", n)); + n <<= 25; + EXPECT_EQ("108000000", fmt::format("{}", n)); +} + template void test_construct_from_double() { fmt::print("warning: double is not IEC559, skipping FP tests\n"); }