guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, master, updated. release_1-9-15-2-g9d4


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, master, updated. release_1-9-15-2-g9d427b2
Date: Thu, 03 Feb 2011 09:46:55 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=9d427b2cc3a7062403d75074760a2b0feb01cb21

The branch, master has been updated
       via  9d427b2cc3a7062403d75074760a2b0feb01cb21 (commit)
       via  041fccf6aa3e0c3015f95e66fdee2db2bfaf42b4 (commit)
      from  9da40741891e7b7d11b75f3b1bc78361a8ba2c7a (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 9d427b2cc3a7062403d75074760a2b0feb01cb21
Author: Mark H Weaver <address@hidden>
Date:   Thu Feb 3 02:08:26 2011 -0500

    Improved exactness handling for complex number parsing
    
    When parsing non-real complex numbers, apply exactness specifiers on
    per-component basis, as is done in PLT Scheme.  For complex numbers
    written in rectangular form, exactness specifiers are applied to the
    real and imaginary parts before calling scm_make_rectangular.  For
    complex numbers written in polar form, exactness specifiers are applied
    to the magnitude and angle before calling scm_make_polar.
    
    There are two kinds of exactness specifiers: forced and implicit.  A
    forced exactness specifier is a "#e" or "#i" prefix at the beginning of
    the entire number, and applies to both components of a complex number.
    "#e" causes each component to be made exact, and "#i" causes each
    component to be made inexact.  If no forced exactness specifier is
    present, then the exactness of each component is determined
    independently by the presence or absence of a decimal point or hash mark
    within that component.  If a decimal point or hash mark is present, the
    component is made inexact, otherwise it is made exact.
    
    After the exactness specifiers have been applied to each component, they
    are passed to either scm_make_rectangular or scm_make_polar to produce
    the final result.  Note that this will result in a real number if the
    imaginary part, magnitude, or angle is an exact 0.
    
    Previously, both forced and implicit exactness specifiers applied to
    the number as a whole _after_ calling scm_make_rectangular or
    scm_make_polar.
    
    For example, (string->number "#i5.0+0i") now does the equivalent of:
    
      (make-rectangular (exact->inexact 5.0) (exact->inexact 0))
    
    which yields 5.0+0.0i.  Previously it did the equivalent of:
    
      (exact->inexact (make-rectangular 5.0 0))
    
    which yielded 5.0.
    
    * libguile/numbers.c (mem2ureal): Receive a forced exactness specifier
      (forced_x), create and maintain our own implicit exactness specifier
      flag local to this component (implicit_x), and apply these exactness
      specifiers within this function.  Previously, we received a pointer to
      an implicit exactness specifier flag from above, and the exactness
      specifiers were applied from within scm_i_string_length.
    
      (mem2complex): Receive a forced exactness specifier parameter and pass
      it down to mem2ureal.  Previously, we passed down a pointer to an
      implicit exactness specifier flag instead.
    
      (scm_i_string_to_number): No longer create an implicit exactness
      specifier flag here, and do not apply exactness specifiers here.  All
      we do here now regarding exactness is to parse the "#e" or "#i" prefix
      (if any) and pass this information down to mem2ureal via mem2complex
      in the form of an explicit exactness specifier (forced_x).
    
      (scm_c_make_polar): If the cosine and sine of the angle are both NaNs
      and the magnitude is zero, return 0.0+0.0i instead of +nan.0+nan.0i.
      This case happens when the angle is not finite.
    
    * test-suite/tests/numbers.test (string->number): Move the test cases
      for non-real complex numbers into a separate table in which the
      expected real and imaginary parts are separate entries.  Add several
      new test cases.

commit 041fccf6aa3e0c3015f95e66fdee2db2bfaf42b4
Author: Mark H Weaver <address@hidden>
Date:   Wed Feb 2 19:32:16 2011 -0500

    Fix non-portable usage of `isinf' in `max' and `min'
    
    * numbers.c: Add new macros DOUBLE_IS_POSITIVE_INFINITY and
      DOUBLE_IS_NEGATIVE_INFINITY.
      (scm_max, scm_min): Use the new macros to detect particular
      infinities.  Previously we checked the return value of `isinf'
      to determine the sign of the infinity, but that is not portable.

-----------------------------------------------------------------------

Summary of changes:
 NEWS                          |   25 ++++++++
 libguile/numbers.c            |  126 +++++++++++++++++++++--------------------
 test-suite/tests/numbers.test |   44 ++++++++++----
 3 files changed, 121 insertions(+), 74 deletions(-)

diff --git a/NEWS b/NEWS
index 6781fa0..27b52ae 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,31 @@ Please send Guile bug reports to address@hidden
 Note: During the 1.9 series, we will keep an incremental NEWS for the
 latest prerelease, and a full NEWS corresponding to 1.8 -> 2.0.
 
+Changes since the 1.9.15 prerelease:
+
+** Improved exactness handling for complex number parsing
+
+When parsing non-real complex numbers, exactness specifiers are now
+applied to each component, as is done in PLT Scheme.  For complex
+numbers written in rectangular form, exactness specifiers are applied
+to the real and imaginary parts before calling scm_make_rectangular.
+For complex numbers written in polar form, exactness specifiers are
+applied to the magnitude and angle before calling scm_make_polar.
+
+Previously, exactness specifiers were applied to the number as a whole
+_after_ calling scm_make_rectangular or scm_make_polar.
+
+For example, (string->number "#i5.0+0i") now does the equivalent of:
+
+  (make-rectangular (exact->inexact 5.0) (exact->inexact 0))
+
+which yields 5.0+0.0i.  Previously it did the equivalent of:
+
+  (exact->inexact (make-rectangular 5.0 0))
+
+which yielded 5.0.
+
+
 Changes in 1.9.15 (since the 1.9.14 prerelease):
 
 ** Formally deprecate omission of port to `format'
diff --git a/libguile/numbers.c b/libguile/numbers.c
index 18d5755..85ca0fd 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -83,6 +83,11 @@ typedef scm_t_signed_bits scm_t_inum;
    TODO: if it's available, use C99's isfinite(x) instead */
 #define DOUBLE_IS_FINITE(x) (!isinf(x) && !isnan(x))
 
+/* On some platforms, isinf(x) returns 0, 1 or -1, indicating the sign
+   of the infinity, but other platforms return a boolean only. */
+#define DOUBLE_IS_POSITIVE_INFINITY(x) (isinf(x) && ((x) > 0))
+#define DOUBLE_IS_NEGATIVE_INFINITY(x) (isinf(x) && ((x) < 0))
+
 
 
 /*
@@ -4119,7 +4124,7 @@ mem2decimal_from_point (SCM result, SCM mem,
 
 static SCM
 mem2ureal (SCM mem, unsigned int *p_idx,
-          unsigned int radix, enum t_exactness *p_exactness)
+          unsigned int radix, enum t_exactness forced_x)
 {
   unsigned int idx = *p_idx;
   SCM result;
@@ -4127,7 +4132,7 @@ mem2ureal (SCM mem, unsigned int *p_idx,
 
   /* Start off believing that the number will be exact.  This changes
      to INEXACT if we see a decimal point or a hash. */
-  enum t_exactness x = EXACT;
+  enum t_exactness implicit_x = EXACT;
 
   if (idx == len)
     return SCM_BOOL_F;
@@ -4143,7 +4148,7 @@ mem2ureal (SCM mem, unsigned int *p_idx,
       /* Cobble up the fractional part.  We might want to set the
         NaN's mantissa from it. */
       idx += 4;
-      mem2uinteger (mem, &idx, 10, &x);
+      mem2uinteger (mem, &idx, 10, &implicit_x);
       *p_idx = idx;
       return scm_nan ();
     }
@@ -4158,13 +4163,13 @@ mem2ureal (SCM mem, unsigned int *p_idx,
        return SCM_BOOL_F;
       else
        result = mem2decimal_from_point (SCM_INUM0, mem,
-                                        p_idx, &x);
+                                        p_idx, &implicit_x);
     }
   else
     {
       SCM uinteger;
 
-      uinteger = mem2uinteger (mem, &idx, radix, &x);
+      uinteger = mem2uinteger (mem, &idx, radix, &implicit_x);
       if (scm_is_false (uinteger))
        return SCM_BOOL_F;
 
@@ -4178,7 +4183,7 @@ mem2ureal (SCM mem, unsigned int *p_idx,
           if (idx == len)
             return SCM_BOOL_F;
 
-         divisor = mem2uinteger (mem, &idx, radix, &x);
+         divisor = mem2uinteger (mem, &idx, radix, &implicit_x);
          if (scm_is_false (divisor))
            return SCM_BOOL_F;
 
@@ -4187,7 +4192,7 @@ mem2ureal (SCM mem, unsigned int *p_idx,
        }
       else if (radix == 10)
        {
-         result = mem2decimal_from_point (uinteger, mem, &idx, &x);
+         result = mem2decimal_from_point (uinteger, mem, &idx, &implicit_x);
          if (scm_is_false (result))
            return SCM_BOOL_F;
        }
@@ -4197,21 +4202,32 @@ mem2ureal (SCM mem, unsigned int *p_idx,
       *p_idx = idx;
     }
 
-  /* Update *p_exactness if the number just read was inexact.  This is
-     important for complex numbers, so that a complex number is
-     treated as inexact overall if either its real or imaginary part
-     is inexact.
-  */
-  if (x == INEXACT)
-    *p_exactness = x;
-
-  /* When returning an inexact zero, make sure it is represented as a
-     floating point value so that we can change its sign. 
-  */
-  if (scm_is_eq (result, SCM_INUM0) && *p_exactness == INEXACT)
-    result = flo0;
+  switch (forced_x)
+    {
+    case EXACT:
+      if (SCM_INEXACTP (result))
+       return scm_inexact_to_exact (result);
+      else
+       return result;
+    case INEXACT:
+      if (SCM_INEXACTP (result))
+       return result;
+      else
+       return scm_exact_to_inexact (result);
+    case NO_EXACTNESS:
+      if (implicit_x == INEXACT)
+       {
+         if (SCM_INEXACTP (result))
+           return result;
+         else
+           return scm_exact_to_inexact (result);
+       }
+      else
+       return result;
+    }
 
-  return result;
+  /* We should never get here */
+  scm_syserror ("mem2ureal");
 }
 
 
@@ -4219,7 +4235,7 @@ mem2ureal (SCM mem, unsigned int *p_idx,
 
 static SCM
 mem2complex (SCM mem, unsigned int idx,
-            unsigned int radix, enum t_exactness *p_exactness)
+            unsigned int radix, enum t_exactness forced_x)
 {
   scm_t_wchar c;
   int sign = 0;
@@ -4244,7 +4260,7 @@ mem2complex (SCM mem, unsigned int idx,
   if (idx == len)
     return SCM_BOOL_F;
 
-  ureal = mem2ureal (mem, &idx, radix, p_exactness);
+  ureal = mem2ureal (mem, &idx, radix, forced_x);
   if (scm_is_false (ureal))
     {
       /* input must be either +i or -i */
@@ -4315,7 +4331,7 @@ mem2complex (SCM mem, unsigned int idx,
              else
                sign = 1;
 
-             angle = mem2ureal (mem, &idx, radix, p_exactness);
+             angle = mem2ureal (mem, &idx, radix, forced_x);
              if (scm_is_false (angle))
                return SCM_BOOL_F;
              if (idx != len)
@@ -4337,7 +4353,7 @@ mem2complex (SCM mem, unsigned int idx,
          else
            {
              int sign = (c == '+') ? 1 : -1;
-             SCM imag = mem2ureal (mem, &idx, radix, p_exactness);
+             SCM imag = mem2ureal (mem, &idx, radix, forced_x);
 
              if (scm_is_false (imag))
                imag = SCM_I_MAKINUM (sign);
@@ -4373,8 +4389,6 @@ scm_i_string_to_number (SCM mem, unsigned int 
default_radix)
   unsigned int idx = 0;
   unsigned int radix = NO_RADIX;
   enum t_exactness forced_x = NO_EXACTNESS;
-  enum t_exactness implicit_x = EXACT;
-  SCM result;
   size_t len = scm_i_string_length (mem);
 
   /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
@@ -4420,37 +4434,9 @@ scm_i_string_to_number (SCM mem, unsigned int 
default_radix)
 
   /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
   if (radix == NO_RADIX)
-    result = mem2complex (mem, idx, default_radix, &implicit_x);
-  else
-    result = mem2complex (mem, idx, (unsigned int) radix, &implicit_x);
-
-  if (scm_is_false (result))
-    return SCM_BOOL_F;
+    radix = default_radix;
 
-  switch (forced_x)
-    {
-    case EXACT:
-      if (SCM_INEXACTP (result))
-       return scm_inexact_to_exact (result);
-      else
-       return result;
-    case INEXACT:
-      if (SCM_INEXACTP (result))
-       return result;
-      else
-       return scm_exact_to_inexact (result);
-    case NO_EXACTNESS:
-    default:
-      if (implicit_x == INEXACT)
-       {
-         if (SCM_INEXACTP (result))
-           return result;
-         else
-           return scm_exact_to_inexact (result);
-       }
-      else
-       return result;
-    }
+  return mem2complex (mem, idx, radix, forced_x);
 }
 
 SCM
@@ -5251,9 +5237,9 @@ scm_max (SCM x, SCM y)
          /* If neither (xx > yy) nor (xx < yy), then
             either they're equal or one is a NaN */
          else if (SCM_UNLIKELY (isnan (xx)))
-           return (isinf (yy) == 1) ? y : x;
+           return DOUBLE_IS_POSITIVE_INFINITY (yy) ? y : x;
          else if (SCM_UNLIKELY (isnan (yy)))
-           return (isinf (xx) == 1) ? x : y;
+           return DOUBLE_IS_POSITIVE_INFINITY (xx) ? x : y;
          /* xx == yy, but handle signed zeroes properly */
          else if (double_is_non_negative_zero (yy))
            return y;
@@ -5411,9 +5397,9 @@ scm_min (SCM x, SCM y)
          /* If neither (xx < yy) nor (xx > yy), then
             either they're equal or one is a NaN */
          else if (SCM_UNLIKELY (isnan (xx)))
-           return (isinf (yy) == -1) ? y : x;
+           return DOUBLE_IS_NEGATIVE_INFINITY (yy) ? y : x;
          else if (SCM_UNLIKELY (isnan (yy)))
-           return (isinf (xx) == -1) ? x : y;
+           return DOUBLE_IS_NEGATIVE_INFINITY (xx) ? x : y;
          /* xx == yy, but handle signed zeroes properly */
          else if (double_is_non_negative_zero (xx))
            return y;
@@ -7155,7 +7141,23 @@ scm_c_make_polar (double mag, double ang)
   s = sin (ang);
   c = cos (ang);
 #endif
-  return scm_c_make_rectangular (mag * c, mag * s);
+
+  /* If s and c are NaNs, this indicates that the angle is a NaN,
+     infinite, or perhaps simply too large to determine its value
+     mod 2*pi.  However, we know something that the floating-point
+     implementation doesn't know:  We know that s and c are finite.
+     Therefore, if the magnitude is zero, return a complex zero.
+
+     The reason we check for the NaNs instead of using this case
+     whenever mag == 0.0 is because when the angle is known, we'd
+     like to return the correct kind of non-real complex zero:
+     +0.0+0.0i, -0.0+0.0i, -0.0-0.0i, or +0.0-0.0i, depending
+     on which quadrant the angle is in.
+  */
+  if (SCM_UNLIKELY (isnan(s)) && isnan(c) && (mag == 0.0))
+    return scm_c_make_rectangular (0.0, 0.0);
+  else
+    return scm_c_make_rectangular (mag * c, mag * s);
 }
 
 SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test
index 96f37df..1c4630e 100644
--- a/test-suite/tests/numbers.test
+++ b/test-suite/tests/numbers.test
@@ -1523,18 +1523,38 @@
                 ("3.1#e0" 3.1)
                 ;; * <digit 10>+ #+ . #* <suffix>
                 ("3#." 30.0) ("3#.e0" 30.0) ("3#.#" 30.0) ("3#.#e0" 30.0)
-                ;; Complex:
-                ("address@hidden" 1) ("address@hidden" 1) ("address@hidden" 1)
-                ("address@hidden" 1.0+0i) ("address@hidden" 1+0.0i) 
("address@hidden" 1.0-0i)
-                ("2+3i" ,(+ 2 (* 3 +i))) ("4-5i" ,(- 4 (* 5 +i)))
-                ("1+i" 1+1i) ("1-i" 1-1i) ("+1i" 0+1i) ("-1i" 0-1i)
-                ("+i" +1i) ("-i" -1i)
-               ("1.0+.1i" 1.0+0.1i)
-               ("1.0-.1i" 1.0-0.1i)
-               (".1+.0i" 0.1+0.0i)
-               ("1.+.0i" 1.0+0.0i)
-               (".1+.1i" 0.1+0.1i)
-               ("1e1+.1i" 10+0.1i)
+               ))
+    #t)
+
+  (pass-if "valid complex number strings"
+    (for-each (lambda (triple)
+                (apply
+                 (lambda (str re im)
+                   (let ((z (string->number str)))
+                     (if (or (eq? z #f)
+                             (not (and (eqv? (real-part z) re)
+                                       (eqv? (imag-part z) im))))
+                        (begin 
+                          (pk str re im)
+                          (throw 'fail)))))
+                 triple))
+              `(("address@hidden" 1 0) ("address@hidden" 1 0) 
("address@hidden" 1 0) ("1/address@hidden" 1/2 0)
+                ("address@hidden" 1.0 0) ("address@hidden" 1.0 0)
+                ("address@hidden" 1 0) ("address@hidden" 1 0) 
("address@hidden" 1 0) ("address@hidden" 1/2 0)
+                ("address@hidden" 1 0) ("address@hidden" 1 0)
+                ("address@hidden" 1.0 0.0) ("address@hidden" 1.0 0.0) 
("address@hidden" 1.0 -0.0) ("#i1/address@hidden" 0.5 0.0)
+                ("address@hidden" 1.0 0.0) ("address@hidden" 1.0 -0.0)
+                ("address@hidden" 1.0 0.0) ("address@hidden" 1.0 -0.0)
+                ("2+3i" 2.0 3.0) ("4-5i" 4.0 -5.0)
+                ("1+i" 1.0 1.0) ("1-i" 1.0 -1.0) ("+1i" 0.0 1.0) ("-1i" 0.0 
-1.0)
+                ("+i" 0.0 1.0) ("-i" 0.0 -1.0)
+               ("1.0+.1i" 1.0 0.1) ("1.0-.1i" 1.0 -0.1)
+               (".1+.0i" 0.1 0.0) ("1.+.0i" 1.0 0.0) (".1+.1i" 0.1 0.1)
+               ("1e1+.1i" 10.0 0.1)
+                ("address@hidden" 0 0) ("address@hidden" 0 0) 
("address@hidden" 0 0)
+                ("address@hidden" 0.0 0.0) ("address@hidden" 0.0 0.0) 
("address@hidden" 0.0 0.0)
+                ("address@hidden" 0.0 0.0) ("address@hidden" 0.0 0.0) 
("address@hidden" 0.0 0.0)
+                ("address@hidden" 0.0 0.0) ("address@hidden" -0.0 0.0) 
("address@hidden" -0.0 -0.0) ("address@hidden" 0.0 -0.0)
                ))
     #t)
 


hooks/post-receive
-- 
GNU Guile



reply via email to

[Prev in Thread] Current Thread [Next in Thread]