exact->inexact fixup for MSVC

Casting a `uintptr_t` to `double` seems not to round to
nearest, so keep all bits while moving to `double` and
use arithmetic to combine them (since the rounding mode
is used correctly for arithmetic).
This commit is contained in:
Matthew Flatt 2015-11-22 08:16:48 -07:00
parent 5691b5a344
commit 2a88662d01
2 changed files with 36 additions and 5 deletions

View File

@ -679,6 +679,7 @@
/* With VC 7, ATAN2_DOESNT... wasn't needed, and
POW_HANDLES_INF_CORRECTLY worked, too. */
# define SIN_COS_NEED_DEOPTIMIZE
# define AVOID_INT_TO_FLOAT_TRUNCATION
#endif
#ifdef __BORLANDC__
# define NAN_EQUALS_ANYTHING
@ -1281,6 +1282,11 @@
/* FLOATING_POINT_IS_NOT_IEEE disables inexact->exact conversion via
parsing of IEEE-format bits. */
/* AVOID_INT_TO_FLOAT_TRUNCATION indicates that conversion from an
integer to a floating point type does not round-to-nearest when
precision is lost, even when the FP rounding mode is
round-to-nearest */
/* USE_SINGLE_FLOATS turns on support for single-precision
floating point numbers. Otherwise, floating point numbers
are always represented in double-precision. */

View File

@ -90,6 +90,7 @@ void scheme_bignum_use_fuel(intptr_t n);
#if defined(SIXTY_FOUR_BIT_INTEGERS) || defined(USE_LONG_LONG_FOR_BIGDIG)
# define BIG_RADIX 18446744073709551616.0 /* = 0x10000000000000000 */
# define BIG_HALF_RADIX 4294967296.0
# define WORD_SIZE 64
#else
# define BIG_RADIX 4294967296.0 /* = 0x100000000 */
@ -1464,10 +1465,21 @@ XFORM_NONGCING static int any_nonzero_digits(bigdig *na, intptr_t nl, int delta)
return 0;
}
#if defined(SIXTY_FOUR_BIT_INTEGERS) && defined(AVOID_INT_TO_FLOAT_TRUNCATION)
XFORM_NONGCING static double double_from_bigdig(bigdig b)
{
double d1, d2;
d1 = (double)(b >> (WORD_SIZE >> 1));
d2 = (double)(b & (((bigdig)1 << (WORD_SIZE >> 1))-1));
return (d1 * BIG_HALF_RADIX) + d2;
}
#endif
#define USE_FLOAT_BITS 53
#define FP_TYPE double
#define FP_TYPE_FROM_DOUBLE(x) (FP_TYPE)x
#define FP_TYPE_FROM_DOUBLE(x) ((FP_TYPE)(x))
#define FP_TYPE_NEG(x) (-(x))
#define FP_TYPE_LESS(x, y) ((x)<(y))
#define FP_TYPE_MULT(x, y) ((x)*(y))
@ -1475,9 +1487,13 @@ XFORM_NONGCING static int any_nonzero_digits(bigdig *na, intptr_t nl, int delta)
#define FP_TYPE_DIV(x, y) ((x)/(y))
#define FP_TYPE_POW(x, y) pow(x, y)
#define FP_TYPE_FROM_INT(x) ((FP_TYPE)(x))
#if defined(SIXTY_FOUR_BIT_INTEGERS) && defined(AVOID_INT_TO_FLOAT_TRUNCATION)
# define FP_TYPE_FROM_UINTPTR(x) double_from_bigdig(x)
#else
# define FP_TYPE_FROM_UINTPTR(x) ((FP_TYPE)(x))
#endif
#define FP_TYPE_GREATER_OR_EQV(x, y) ((x)>=(y))
#define FP_TYPE_MINUS(x, y) ((x)-(y))
#define FP_TYPE_FROM_UINTPTR
#define IS_FLOAT_INF scheme__is_double_inf
#define SCHEME_BIGNUM_TO_FLOAT_INFO scheme_bignum_to_double_inf_info
@ -1490,17 +1506,26 @@ XFORM_NONGCING static int any_nonzero_digits(bigdig *na, intptr_t nl, int delta)
# define USE_FLOAT_BITS 24
# define FP_TYPE float
# define FP_TYPE_FROM_DOUBLE(x) (FP_TYPE)x
#define FP_TYPE_FROM_DOUBLE(x) ((FP_TYPE)(x))
#define FP_TYPE_NEG(x) (-(x))
#define FP_TYPE_LESS(x, y) ((x)<(y))
#define FP_TYPE_MULT(x, y) ((x)*(y))
#define FP_TYPE_PLUS(x, y) ((x)+(y))
#define FP_TYPE_DIV(x, y) ((x)/(y))
#define FP_TYPE_POW(x, y) pow(x, y)
#define FP_TYPE_FROM_INT(x) ((FP_TYPE)(x))
#if defined(AVOID_INT_TO_FLOAT_TRUNCATION)
# if defined(SIXTY_FOUR_BIT_INTEGERS)
# define FP_TYPE_FROM_UINTPTR(x) ((FP_TYPE)double_from_bigdig(x))
# else
# define FP_TYPE_FROM_UINTPTR(x) (FP_TYPE)((double)(x))
# endif
# define FP_TYPE_FROM_INT(x) (FP_TYPE)((double)(x))
#else
# define FP_TYPE_FROM_UINTPTR(x) ((FP_TYPE)(x))
# define FP_TYPE_FROM_INT(x) ((FP_TYPE)(x))
#endif
#define FP_TYPE_GREATER_OR_EQV(x, y) ((x)>=(y))
#define FP_TYPE_MINUS(x, y) ((x)-(y))
# define FP_TYPE_FROM_UINTPTR
# define IS_FLOAT_INF scheme__is_float_inf
# define SCHEME_BIGNUM_TO_FLOAT_INFO scheme_bignum_to_float_inf_info