diff --git a/collects/tests/racket/number.rktl b/collects/tests/racket/number.rktl index 2977faa22b..b604a48b9f 100644 --- a/collects/tests/racket/number.rktl +++ b/collects/tests/racket/number.rktl @@ -2980,6 +2980,79 @@ (err/rt-test (real->floating-point-bytes 1.0+2.0i 8)) (err/rt-test (real->floating-point-bytes 1.0 8 #f (make-bytes 7)) exn:application:mismatch?) +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Check single-flonum coercisons: + +(define ((check-single-flonum #:real-only? [real-only? #f] + #:integer-only? [integer-only? #f] + #:two-arg-real-only? [two-arg-real-only? real-only?]) + op) + (define (single-flonum-ish? op . args) + (define v (apply op args)) + (and (or (single-flonum? (real-part v)) + (eq? 0 (real-part v))) + (or (single-flonum? (imag-part v)) + (eq? 0 (imag-part v))))) + (when (procedure-arity-includes? op 1) + (test #t single-flonum-ish? op 2.0f0) + (unless real-only? + (test #t single-flonum-ish? op 2.0f0+4.0f0i) + (test #t single-flonum-ish? op 0+4.0f0i))) + (when (procedure-arity-includes? op 2) + (test #t single-flonum-ish? op 2.0f0 4.0f0) + (test #f single-flonum-ish? op 2.0 4.0f0) + (test #f single-flonum-ish? op 2.0f0 4.0) + (test #t single-flonum-ish? op 2.0f0 4) + (test #t single-flonum-ish? op 2 4.0f0) + (unless integer-only? + (unless two-arg-real-only? + (test #t single-flonum-ish? op 2.0f0 2.0f0+4.0f0i) + (test #t single-flonum-ish? op 2.0f0 0+4.0f0i) + (test #f single-flonum-ish? op 2.0f0 2.0+4.0i) + (test #f single-flonum-ish? op 2.0f0 0+4.0i) + (test #f single-flonum-ish? op 2.0 2.0f0+4.0f0i) + (test #f single-flonum-ish? op 2.0 0+4.0f0i)) + (test #t single-flonum-ish? op 2.0f0 0.5f0) + (test #f single-flonum-ish? op 2.0 0.5f0) + (test #f single-flonum-ish? op 2.0f0 0.5) + (test #t single-flonum-ish? op 2.0f0 1/2) + (test #t single-flonum-ish? op 4/5 0.5f0)))) + + +(map (check-single-flonum) + (list + - * / + add1 + sub1 + sqrt + expt + exp + log + sin + cos + tan + asin + acos)) + +(map (check-single-flonum #:two-arg-real-only? #t) + (list atan)) + +(map (check-single-flonum #:real-only? #f #:integer-only? #t) + (list quotient + remainder + modulo)) + +(map (check-single-flonum #:real-only? #t) + (list + abs + max + min + gcd + lcm + round + floor + ceiling + truncate)) + ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This test once trigggered a crash due to an incorrect ;; hard-wired GC declaration for xform: diff --git a/src/racket/src/complex.c b/src/racket/src/complex.c index f1e0d6b3a5..686b232f44 100644 --- a/src/racket/src/complex.c +++ b/src/racket/src/complex.c @@ -328,15 +328,14 @@ Scheme_Object *scheme_complex_power(const Scheme_Object *base, const Scheme_Obje #ifdef MZ_USE_SINGLE_FLOATS /* Coerce to double or float? */ -#ifdef USE_SINGLE_FLOATS_AS_DEFAULT if (!SCHEME_DBLP(cb->r) && !SCHEME_DBLP(cb->i) && !SCHEME_DBLP(ce->r) && !SCHEME_DBLP(ce->i)) -#else - if (SCHEME_FLTP(cb->r) && SCHEME_FLTP(cb->i) - && SCHEME_FLTP(ce->r) && SCHEME_FLTP(ce->i)) +#ifndef USE_SINGLE_FLOATS_AS_DEFAULT + if (SCHEME_FLTP(cb->r) || SCHEME_FLTP(cb->i) + || SCHEME_FLTP(ce->r) || SCHEME_FLTP(ce->i)) #endif - return scheme_make_complex(scheme_make_float((float)r1), - scheme_make_float((float)r2)); + return scheme_make_complex(scheme_make_float((float)r1), + scheme_make_float((float)r2)); #endif return scheme_make_complex(scheme_make_double(r1), @@ -380,9 +379,15 @@ Scheme_Object *scheme_complex_sqrt(const Scheme_Object *o) if (SCHEME_FLOATP(srssq)) { /* We may have lost too much precision, if i << r. The result is going to be inexact, anyway, so switch to using expt. */ - Scheme_Object *a[2]; + Scheme_Object *a[2], *p; a[0] = (Scheme_Object *)o; - a[1] = scheme_make_double(0.5); +#ifdef MZ_USE_SINGLE_FLOATS + if (SCHEME_FLTP(c->i)) + p = scheme_make_float(0.5); + else +#endif + p = scheme_make_double(0.5); + a[1] = p; return scheme_expt(2, a); } diff --git a/src/racket/src/number.c b/src/racket/src/number.c index f2cf488fdc..d10ff08c84 100644 --- a/src/racket/src/number.c +++ b/src/racket/src/number.c @@ -183,7 +183,7 @@ READ_ONLY Scheme_Object *scheme_inf_object, *scheme_minus_inf_object, *scheme_na READ_ONLY Scheme_Object *scheme_zerod, *scheme_nzerod, *scheme_pi, *scheme_half_pi, *scheme_plus_i, *scheme_minus_i; #ifdef MZ_USE_SINGLE_FLOATS -READ_ONLY Scheme_Object *scheme_zerof, *scheme_nzerof, *scheme_single_pi; +READ_ONLY Scheme_Object *scheme_zerof, *scheme_nzerof, *scheme_single_pi, *scheme_single_half_pi; READ_ONLY Scheme_Object *scheme_single_inf_object, *scheme_single_minus_inf_object, *scheme_single_nan_object; #endif @@ -266,6 +266,7 @@ scheme_init_number (Scheme_Env *env) REGISTER_SO(scheme_nzerod); #ifdef MZ_USE_SINGLE_FLOATS REGISTER_SO(scheme_single_pi); + REGISTER_SO(scheme_single_half_pi); REGISTER_SO(scheme_zerof); REGISTER_SO(scheme_nzerof); #endif @@ -311,7 +312,8 @@ scheme_init_number (Scheme_Env *env) #ifdef MZ_USE_SINGLE_FLOATS scheme_zerof = scheme_make_float(0.0f); scheme_nzerof = scheme_make_float(-0.0f); - scheme_single_pi = scheme_make_float((float)atan2(0.0, -1.0)); + scheme_single_pi = scheme_make_float(SCHEME_DBL_VAL(scheme_pi)); + scheme_single_half_pi = scheme_make_float(SCHEME_DBL_VAL(scheme_half_pi)); #endif scheme_plus_i = scheme_make_complex(scheme_make_integer(0), scheme_make_integer(1)); scheme_minus_i = scheme_make_complex(scheme_make_integer(0), scheme_make_integer(-1)); @@ -1699,11 +1701,7 @@ scheme_bin_gcd (const Scheme_Object *n1, const Scheme_Object *n2) } else if (SCHEME_FLOATP(n1) || SCHEME_FLOATP(n2)) { double i1, i2, a, b, r; #ifdef MZ_USE_SINGLE_FLOATS -# ifdef USE_SINGLE_FLOATS_AS_DEFAULT int was_single = !(SCHEME_DBLP(n1) || SCHEME_DBLP(n2)); -# else - int was_single = (SCHEME_FLTP(n1) || SCHEME_FLTP(n2)); -# endif #endif if (SCHEME_INTP(n1)) @@ -2106,6 +2104,18 @@ static Scheme_Object *get_frac(char *name, int low_p, return n; } +#ifdef USE_SINGLE_FLOATS +XFORM_NONGCING static int complex_single_flonum_p(Scheme_Object *c) +{ + Scheme_Complex *cb = (Scheme_Complex *)c; + + if (SCHEME_FLTP(cb->r) || SCHEME_FLTP(cb->i)) + return 1; + + return 0; +} +#endif + static Scheme_Object *un_exp(Scheme_Object *o); static Scheme_Object *un_log(Scheme_Object *o); @@ -2243,30 +2253,45 @@ static Scheme_Object *complex_acos(Scheme_Object *c) && (scheme_bin_gt(_scheme_complex_real_part(c), scheme_make_integer(1)) || scheme_bin_lt(_scheme_complex_real_part(c), scheme_make_integer(-1)))) { /* Make sure real part is 0 or pi */ - if (scheme_is_negative(_scheme_complex_real_part(c))) - r = scheme_pi; - else + if (scheme_is_negative(_scheme_complex_real_part(c))) { +#ifdef MZ_USE_SINGLE_FLOATS + if (complex_single_flonum_p(c)) + r = scheme_single_pi; + else +#endif + r = scheme_pi; + } else r = scheme_make_integer(0); return scheme_make_complex(r, scheme_bin_minus(scheme_make_integer(0), _scheme_complex_imaginary_part(a))); } else { - return scheme_bin_minus(scheme_half_pi, a); +#ifdef MZ_USE_SINGLE_FLOATS + if (complex_single_flonum_p(c)) + r = scheme_single_half_pi; + else +#endif + r = scheme_half_pi; + return scheme_bin_minus(r, a); } } static Scheme_Object *complex_atan(Scheme_Object *c) { + Scheme_Object *one_half = NULL; + if (scheme_complex_eq(c, scheme_plus_i) || scheme_complex_eq(c, scheme_minus_i)) return scheme_minus_inf_object; - return scheme_bin_mult(scheme_plus_i, - scheme_bin_mult( -#ifdef USE_SINGLE_FLOATS_AS_DEFAULT - scheme_make_float(0.5) -#else - scheme_make_double(0.5) + /* select single versus complex: */ +#ifdef MZ_USE_SINGLE_FLOATS + if (complex_single_flonum_p(c)) + one_half = scheme_make_float(0.5); + else #endif - , + one_half = scheme_make_double(0.5); + + return scheme_bin_mult(scheme_plus_i, + scheme_bin_mult(one_half, un_log(scheme_bin_div(scheme_bin_plus(scheme_plus_i, c), scheme_bin_plus(scheme_plus_i, scheme_bin_minus(zeroi, c)))))); @@ -2357,13 +2382,12 @@ atan_prim (int argc, Scheme_Object *argv[]) double v; Scheme_Object *n1; #ifdef MZ_USE_SINGLE_FLOATS + int dbl = 0, sgl = 0; # ifdef USE_SINGLE_FLOATS_AS_DEFAULT - int dbl = 0; -# define MZ_USE_SINGLE !dbl +# define MZ_USE_SINGLE !dbl # else - int sgl = 0; -# define MZ_USE_SINGLE sgl == 2 -#endif +# define MZ_USE_SINGLE (sgl && !dbl) +# endif #endif n1 = argv[0]; @@ -2373,15 +2397,13 @@ atan_prim (int argc, Scheme_Object *argv[]) #ifdef MZ_USE_SINGLE_FLOATS else if (SCHEME_FLTP(n1)) { v = SCHEME_FLT_VAL(n1); -# ifndef USE_SINGLE_FLOATS_AS_DEFAULT sgl++; -# endif } #endif else if (SCHEME_DBLP(n1)) { -# ifdef USE_SINGLE_FLOATS_AS_DEFAULT +#ifdef MZ_USE_SINGLE_FLOATS dbl++; -# endif +#endif v = SCHEME_DBL_VAL(n1); } else if (SCHEME_BIGNUMP(n1)) v = scheme_bignum_to_double(n1); @@ -2421,15 +2443,13 @@ atan_prim (int argc, Scheme_Object *argv[]) #ifdef MZ_USE_SINGLE_FLOATS else if (SCHEME_FLTP(n2)) { v2 = SCHEME_FLT_VAL(n2); -# ifndef USE_SINGLE_FLOATS_AS_DEFAULT sgl++; -# endif } #endif else if (SCHEME_DBLP(n2)) { -# ifdef USE_SINGLE_FLOATS_AS_DEFAULT +#ifdef MZ_USE_SINGLE_FLOATS dbl++; -# endif +#endif v2 = SCHEME_DBL_VAL(n2); } else if (SCHEME_BIGNUMP(n2)) v2 = scheme_bignum_to_double(n2); @@ -2481,12 +2501,6 @@ atan_prim (int argc, Scheme_Object *argv[]) return zeroi; v = SCH_ATAN(v); - -#ifdef MZ_USE_SINGLE_FLOATS -# ifndef USE_SINGLE_FLOATS_AS_DEFAULT - sgl++; /* sgl needs to be 2 to return a single-precision result */ -# endif -#endif } #ifdef MZ_USE_SINGLE_FLOATS