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

This commit is contained in:
Alex Dyachenko 2019-06-28 12:18:19 -04:00
parent 36cdf4ad96
commit 5aab0cf7b0
4 changed files with 70 additions and 9 deletions

View File

@ -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

View File

@ -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);

View File

@ -1025,12 +1025,11 @@ namespace MPIR
/// </para></summary>
/// <param name="exp">variable to store the exponent in.</param>
/// <returns>The mantissa of the value as a double, possibly truncated.</returns>
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

View File

@ -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);