From 422d5579b3fe3b66bfbdd74694a697e99d8a1909 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Thu, 17 Jan 2019 19:57:22 -0700 Subject: [PATCH] atan: exception on exact 0+1i or 0-1i, exact 0 on positive x Change from treating exact 0+1i and 0-1i like the corresponding inexact values. Also, change from treating `(atan 0 x)` as exact 0 only when x is exact. That's consistent with `angle` producing exact 0 for a positive real number. --- .../scribblings/reference/numbers.scrbl | 11 ++++++--- .../racket-test-core/tests/racket/number.rktl | 8 ++++--- racket/src/racket/src/number.c | 23 +++++++++++++++---- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/pkgs/racket-doc/scribblings/reference/numbers.scrbl b/pkgs/racket-doc/scribblings/reference/numbers.scrbl index 286e275ce9..bb91fc4c1b 100644 --- a/pkgs/racket-doc/scribblings/reference/numbers.scrbl +++ b/pkgs/racket-doc/scribblings/reference/numbers.scrbl @@ -704,7 +704,8 @@ Returns the arccosine in radians of @racket[z]. In the one-argument case, returns the arctangent of the inexact approximation of @racket[z], except that the result is an exact - @racket[0] for an exact @racket[0] argument. + @racket[0] for @racket[z] as @racket[0], and the @exnraise[exn:fail:contract:divide-by-zero] + for @racket[z] as exact @racket[0+1i] or exact @racket[0-1i]. In the two-argument case, the result is roughly the same as @racket[ (atan (/ (exact->inexact y)) (exact->inexact x))], but the signs of @racket[y] @@ -712,11 +713,15 @@ In the two-argument case, the result is roughly the same as @racket[ suitable angle is returned when @racket[y] divided by @racket[x] produces @racket[+nan.0] in the case that neither @racket[y] nor @racket[x] is @racket[+nan.0]. Finally, if @racket[y] is exact - @racket[0] and @racket[x] is an exact positive number, the result is + @racket[0] and @racket[x] is a positive number, the result is exact @racket[0]. If both @racket[x] and @racket[y] are exact @racket[0], the @exnraise[exn:fail:contract:divide-by-zero]. -@mz-examples[(atan 0.5) (atan 2 1) (atan -2 -1) (atan 1+05.i) (atan +inf.0 -inf.0)]} +@mz-examples[(atan 0.5) (atan 2 1) (atan -2 -1) (atan 1+05.i) (atan +inf.0 -inf.0)] + +@history[#:changed "7.2.0.2" @elem{Changed to raise @racket[exn:fail:contract:divide-by-zero] + for @racket[0+1i] and @racket[0-1i] and to produce exact @racket[0] + for any positive @racket[x] (not just exact values) when @racket[y] is @racket[0].}]} @; ------------------------------------------------------------------------ @subsection{Complex Numbers} diff --git a/pkgs/racket-test-core/tests/racket/number.rktl b/pkgs/racket-test-core/tests/racket/number.rktl index a912be2fa7..bf1afa5a1a 100644 --- a/pkgs/racket-test-core/tests/racket/number.rktl +++ b/pkgs/racket-test-core/tests/racket/number.rktl @@ -1669,8 +1669,6 @@ (test pi angle (- big-num)) (test pi angle -3/4) (test pi angle -3+0.0i)) -(test -inf.0 atan 0+i) -(test -inf.0 atan 0-i) (err/rt-test (angle 'a)) (err/rt-test (angle 0) exn:fail:contract:divide-by-zero?) @@ -2098,9 +2096,13 @@ (test 0 atan 0 1) (test 0 atan 0 (expt 2 100)) (test 0 atan 0 5/2) -(test 0.0 atan 0 1.0) +(test 0 atan 0 1.0) (test 314.0 round (* 100 (atan 0 -1))) (err/rt-test (atan 0 0) exn:fail:contract:divide-by-zero?) +(err/rt-test (atan 0+i) exn:fail:contract:divide-by-zero?) +(err/rt-test (atan 0-i) exn:fail:contract:divide-by-zero?) +(test -inf.0 atan 0+1.0i) +(test -inf.0 atan 0-1.0i) (test 1024.0 round (expt 2.0 10.0)) (test 1024.0 round (expt -2.0 10.0)) (test -512.0 round (expt -2.0 9.0)) diff --git a/racket/src/racket/src/number.c b/racket/src/racket/src/number.c index 2fa3297f6e..954efffbf1 100644 --- a/racket/src/racket/src/number.c +++ b/racket/src/racket/src/number.c @@ -2913,8 +2913,23 @@ 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; + if (SAME_OBJ(_scheme_complex_real_part(c), scheme_make_integer(0))) { + Scheme_Object *i = _scheme_complex_imaginary_part(c); + if (SAME_OBJ(i, scheme_make_integer(1)) || SAME_OBJ(i, scheme_make_integer(-1))) { + scheme_raise_exn(MZEXN_FAIL_CONTRACT_DIVIDE_BY_ZERO, "atan: undefined for %V", c); + return NULL; +#ifdef MZ_USE_SINGLE_FLOATS + } else if (SCHEME_FLTP(i)) { + float f = SCHEME_FLT_VAL(i); + if ((f == 1.0) || (f == -1.0)) + return scheme_single_minus_inf_object; +#endif + } else if (SCHEME_DBLP(i)) { + double d = SCHEME_DBL_VAL(i); + if ((d == 1.0) || (d == -1.0)) + return scheme_minus_inf_object; + } + } /* select single versus complex: */ #ifdef MZ_USE_SINGLE_FLOATS @@ -3115,9 +3130,7 @@ atan_prim (int argc, Scheme_Object *argv[]) "atan: undefined for 0 and 0"); ESCAPED_BEFORE_HERE; } - if ((SCHEME_INTP(n2) && (SCHEME_INT_VAL(n2) > 0)) - || (SCHEME_BIGNUMP(n2) && (SCHEME_BIGPOS(n2))) - || (SCHEME_RATIONALP(n2) && scheme_is_positive(n2))) + if (!SCHEME_COMPLEXP(n2) && scheme_is_positive(n2)) return zeroi; }