diff --git a/include/boost/decimal/detail/cmath/impl/trig_reduce.hpp b/include/boost/decimal/detail/cmath/impl/trig_reduce.hpp index 5455f31b2..443588965 100644 --- a/include/boost/decimal/detail/cmath/impl/trig_reduce.hpp +++ b/include/boost/decimal/detail/cmath/impl/trig_reduce.hpp @@ -248,12 +248,8 @@ constexpr auto to_words(const boost::int128::uint128_t& m, std::uint64_t* out) n out[1] = lo / word_base; out[2] = hi % word_base; out[3] = hi / word_base; - int n {4}; - while (n > 0 && out[n - 1] == 0U) - { - --n; - } - return n; + // Zero high words do not change the product. + return 4; } // m * 10^shift in words of 9 digits, low word first, for 0 <= shift < 9; returns the count of words. @@ -436,17 +432,12 @@ constexpr auto trig_reduce(const Significand m, const int e, const bool xneg) no out.n = n; out.neg = rneg; + // The fraction is not zero: its worst case has 9, 19 and 37 leading zero digits (see trig_traits). int lead {}; while (lead < window - 1 && f[lead] == 0U) { ++lead; } - if (lead == window - 1) - { - // Only for an exact multiple of pi/2, which no nonzero x is. - out.zero = true; - return out; - } std::uint64_t r[static_cast(2 * frac + 1)] {}; times_half_pi(f, lead, r); @@ -573,17 +564,12 @@ constexpr auto trig_reduce_binary(const Significand m, const int e, const bool x out.n = n; out.neg = rneg; + // The fraction is not zero: its worst case has 27, 58 and 117 leading zero bits (see trig_traits). int lead {}; while (lead < frac && f[lead] == 0U) { ++lead; } - if (lead == frac) - { - // Only for an exact multiple of pi/2, which no nonzero x is. - out.zero = true; - return out; - } // r = (rw words of f from word lead) * pi/2 = (s from word rw) * 2^-64(lead + rw). The four spare // words take the scale by 10^k below. diff --git a/test/test_trig_rounding.cpp b/test/test_trig_rounding.cpp index 163e1ac76..9fb173b39 100644 --- a/test/test_trig_rounding.cpp +++ b/test/test_trig_rounding.cpp @@ -15,7 +15,7 @@ using namespace boost::decimal; using namespace boost::decimal::literals; // Each type has inputs near pi/2, pi and 1000*pi/2, the value nearest to a multiple of pi/2 in its exponent -// range (4.327189e+48 for decimal32_t) and below 10^19 (76.96902), and the inputs on each side of 10^19. +// range (4.327189e+48 for decimal32_t) and below 10^19 (76.96902), the inputs on each side of 10^19, -10^19 and 10^-80. template void check(const T x, const T s, const T c, const T t) { @@ -41,6 +41,8 @@ void test_nearest_decimal32_t() check(7.696902e+01_DF, 1.000000e0_DF, 1.294993e-8_DF, 7.722047e7_DF); check(9.999999e+18_DF, -9.628773e-1_DF, 2.699396e-1_DF, -3.567010e0_DF); check(1.000000e+19_DF, -9.270632e-1_DF, -3.749052e-1_DF, 2.472794e0_DF); + check(-1.000000e+19_DF, 9.270632e-1_DF, -3.749052e-1_DF, -2.472794e0_DF); + check(1.000000e-80_DF, 1.000000e-80_DF, 1.000000e0_DF, 1.000000e-80_DF); } void test_nearest_decimal_fast32_t() @@ -60,6 +62,8 @@ void test_nearest_decimal_fast32_t() check(7.696902e+01_DFF, 1.000000e0_DFF, 1.294993e-8_DFF, 7.722047e7_DFF); check(9.999999e+18_DFF, -9.628773e-1_DFF, 2.699396e-1_DFF, -3.567010e0_DFF); check(1.000000e+19_DFF, -9.270632e-1_DFF, -3.749052e-1_DFF, 2.472794e0_DFF); + check(-1.000000e+19_DFF, 9.270632e-1_DFF, -3.749052e-1_DFF, -2.472794e0_DFF); + check(1.000000e-80_DFF, 1.000000e-80_DFF, 1.000000e0_DFF, 1.000000e-80_DFF); } void test_nearest_decimal64_t() @@ -79,6 +83,8 @@ void test_nearest_decimal64_t() check(9.538513039607291e+06_DD, -6.771756623504492e-18_DD, -1.000000000000000e0_DD, 6.771756623504492e-18_DD); check(9.999999999999999e+18_DD, -2.113595126444045e-1_DD, -9.774083877349937e-1_DD, 2.162448320442599e-1_DD); check(1.000000000000000e+19_DD, -9.270631660486504e-1_DD, -3.749051695507178e-1_DD, 2.472793765846527e0_DD); + check(-1.000000000000000e+19_DD, 9.270631660486504e-1_DD, -3.749051695507178e-1_DD, -2.472793765846527e0_DD); + check(1.000000000000000e-80_DD, 1.000000000000000e-80_DD, 1.000000000000000e0_DD, 1.000000000000000e-80_DD); } void test_nearest_decimal_fast64_t() @@ -98,6 +104,8 @@ void test_nearest_decimal_fast64_t() check(9.538513039607291e+06_DDF, -6.771756623504492e-18_DDF, -1.000000000000000e0_DDF, 6.771756623504492e-18_DDF); check(9.999999999999999e+18_DDF, -2.113595126444045e-1_DDF, -9.774083877349937e-1_DDF, 2.162448320442599e-1_DDF); check(1.000000000000000e+19_DDF, -9.270631660486504e-1_DDF, -3.749051695507178e-1_DDF, 2.472793765846527e0_DDF); + check(-1.000000000000000e+19_DDF, 9.270631660486504e-1_DDF, -3.749051695507178e-1_DDF, -2.472793765846527e0_DDF); + check(1.000000000000000e-80_DDF, 1.000000000000000e-80_DDF, 1.000000000000000e0_DDF, 1.000000000000000e-80_DDF); } void test_nearest_decimal128_t() @@ -117,6 +125,8 @@ void test_nearest_decimal128_t() check(2.589477332551582209163675623249625e+08_DL, -1.000000000000000000000000000000000e0_DL, 1.532138639232766081410107492878833e-35_DL, -6.526824494816997196224318392388852e34_DL); check(9.999999999999999999999999999999999e+18_DL, -9.270631660486500103289527389466423e-1_DL, -3.749051695507187572163865946598085e-1_DL, 2.472793765846520245629178386203776e0_DL); check(1.000000000000000000000000000000000e+19_DL, -9.270631660486503852341222896649360e-1_DL, -3.749051695507178301532205460096107e-1_DL, 2.472793765846527360338186795636566e0_DL); + check(-1.000000000000000000000000000000000e+19_DL, 9.270631660486503852341222896649360e-1_DL, -3.749051695507178301532205460096107e-1_DL, -2.472793765846527360338186795636566e0_DL); + check(1.000000000000000000000000000000000e-80_DL, 1.000000000000000000000000000000000e-80_DL, 1.000000000000000000000000000000000e0_DL, 1.000000000000000000000000000000000e-80_DL); } void test_nearest_decimal_fast128_t() @@ -136,6 +146,8 @@ void test_nearest_decimal_fast128_t() check(2.589477332551582209163675623249625e+08_DLF, -1.000000000000000000000000000000000e0_DLF, 1.532138639232766081410107492878833e-35_DLF, -6.526824494816997196224318392388852e34_DLF); check(9.999999999999999999999999999999999e+18_DLF, -9.270631660486500103289527389466423e-1_DLF, -3.749051695507187572163865946598085e-1_DLF, 2.472793765846520245629178386203776e0_DLF); check(1.000000000000000000000000000000000e+19_DLF, -9.270631660486503852341222896649360e-1_DLF, -3.749051695507178301532205460096107e-1_DLF, 2.472793765846527360338186795636566e0_DLF); + check(-1.000000000000000000000000000000000e+19_DLF, 9.270631660486503852341222896649360e-1_DLF, -3.749051695507178301532205460096107e-1_DLF, -2.472793765846527360338186795636566e0_DLF); + check(1.000000000000000000000000000000000e-80_DLF, 1.000000000000000000000000000000000e-80_DLF, 1.000000000000000000000000000000000e0_DLF, 1.000000000000000000000000000000000e-80_DLF); } void test_downward_decimal32_t()