From 5aab0cf7b0958c59b21205cf0338fa7c6e324b58 Mon Sep 17 00:00:00 2001 From: Alex Dyachenko Date: Fri, 28 Jun 2019 12:18:19 -0400 Subject: [PATCH] Corrected mpf_get_2exp_d on Win64 when the exponent in limbs fits in mp_bit_cnt but the exponent in bits (as returned by this API) does not --- mpf/get_d_2exp.c | 2 +- .../HugeFloatTests/Conversions.cs | 30 +++++++++++++-- mpir.net/mpir.net/HugeFloat.h | 9 ++--- tests/mpf/t-get_d_2exp.c | 38 +++++++++++++++++++ 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/mpf/get_d_2exp.c b/mpf/get_d_2exp.c index f073bfe2..da54413b 100644 --- a/mpf/get_d_2exp.c +++ b/mpf/get_d_2exp.c @@ -47,7 +47,7 @@ mpf_get_2exp_d (double *r, mpf_srcptr src) *r = mpn_get_d (ptr, abs_size, size, (long) - (abs_size * GMP_NUMB_BITS - cnt)); - return EXP(src) * GMP_NUMB_BITS - cnt; + return (mpir_si)EXP(src) * GMP_NUMB_BITS - cnt; } double diff --git a/mpir.net/mpir.net-tests/HugeFloatTests/Conversions.cs b/mpir.net/mpir.net-tests/HugeFloatTests/Conversions.cs index b8767656..b1626199 100644 --- a/mpir.net/mpir.net-tests/HugeFloatTests/Conversions.cs +++ b/mpir.net/mpir.net-tests/HugeFloatTests/Conversions.cs @@ -107,7 +107,7 @@ namespace MPIR.Tests.HugeFloatTests using (var a = new HugeFloat()) { a.SetTo(-123.25); - var exp = 0; + var exp = Platform.Si(0, 0); double c = a.ToDouble(out exp); Assert.IsTrue(c.Equals(-0.962890625)); Assert.AreEqual(7L, exp); @@ -116,6 +116,30 @@ namespace MPIR.Tests.HugeFloatTests } } + [TestMethod] + public void FloatFromDoubleWithLargeExponent() + { + using (var a = new HugeFloat()) + { + var exp = Platform.Si(0, 0); + double mantissa; + + a.SetTo(3); + a.Value = a << Platform.Ui(0x1F65432FD9, 0x7F654329); + + mantissa = a.ToDouble(out exp); + Assert.IsTrue(mantissa.Equals(0.75)); + Assert.AreEqual(Platform.Si(0x1F65432FDB, 0x7F65432B), exp); + + a.SetTo(-3); + a.Value = a >> Platform.Ui(0x1F65432FDD, 0x7F65432D); + + mantissa = a.ToDouble(out exp); + Assert.IsTrue(mantissa.Equals(-0.75)); + Assert.AreEqual(Platform.Si(-0x1F65432FDB, -0x7F65432B), exp); + } + } + [TestMethod] public void FloatToAndFromFloat() { @@ -196,12 +220,12 @@ namespace MPIR.Tests.HugeFloatTests using(var a = new HugeFloat()) { a.SetTo(-123.45e20); - var exp = 0; + var exp = Platform.Si(0, 0); var zillion = Platform.Si(10000000000, 1000000000); a.Value = a + a; double c = a.ToDouble(out exp); - Assert.AreEqual(75, exp); + Assert.AreEqual(Platform.Si(75, 75), exp); c *= Math.Pow(2, exp); Assert.IsTrue(a + zillion >= c); diff --git a/mpir.net/mpir.net/HugeFloat.h b/mpir.net/mpir.net/HugeFloat.h index 13d16a84..b4336529 100644 --- a/mpir.net/mpir.net/HugeFloat.h +++ b/mpir.net/mpir.net/HugeFloat.h @@ -1025,12 +1025,11 @@ namespace MPIR /// /// variable to store the exponent in. /// The mantissa of the value as a double, possibly truncated. - double ToDouble([Out] mp_exp_t% exp) + double ToDouble([Out] mpir_si% exp) { - mp_exp_t x; - auto result = MP(get_d_2exp)(&x, _value); - exp = x; - return result; + double x; + exp = MP(get_2exp_d)(&x, _value); + return x; } #pragma endregion diff --git a/tests/mpf/t-get_d_2exp.c b/tests/mpf/t-get_d_2exp.c index 2459fbc5..ac2b9571 100644 --- a/tests/mpf/t-get_d_2exp.c +++ b/tests/mpf/t-get_d_2exp.c @@ -109,6 +109,43 @@ check_round (void) tests_hardware_setround (old_rnd_mode); } +static void +check_large_exponent(void) +{ +#ifdef _WIN64 + static const mpir_si data[] = { 0x1F789ABCDE, 0x1FFFFFFFBF, -0x1FEDCBA987, -0x1FFFFFFFC1 }; + mpf_t f; + double got; + mpir_si got_exp; + unsigned int i; + + mpf_init2 (f, 1024L); + + for (i = 0; i < numberof (data); i++) + { + mpf_set_ui (f, 1L); + if (data[i] > 0) + { + mpf_mul_2exp(f, f, data[i]); + } + else + { + mpf_div_2exp(f, f, -data[i]); + } + got_exp = mpf_get_2exp_d (&got, f); + if (got != 0.5 || got_exp != data[i] + 1) + { + printf ("mpf_get_2exp_d bad on 2**%lld\n", data[i]); + printf ("result incorrect, expect mantissa = 0.5, exp = %lld\n", data[i] + 1); + mpf_trace (" f ", f); + d_trace (" got ", got); + printf (" got exp %lld\n", got_exp); + abort(); + } + } + mpf_clear (f); +#endif +} int main (void) @@ -118,6 +155,7 @@ main (void) check_onebit (); check_round (); + check_large_exponent (); tests_end (); exit (0);