* device/lib/_fsdiv.c,
authorMaartenBrock <MaartenBrock@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Tue, 25 Jul 2006 23:20:31 +0000 (23:20 +0000)
committerMaartenBrock <MaartenBrock@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Tue, 25 Jul 2006 23:20:31 +0000 (23:20 +0000)
* device/lib/_fsmul.c: bugfix, handle too large and too small numbers
* support/regression/tests/bug1520966.c: added

git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@4302 4a8a32a2-be11-0410-ad9d-d568d2c75423

ChangeLog
device/lib/_fsdiv.c
device/lib/_fsmul.c
support/regression/tests/bug1520966.c [new file with mode: 0644]

index 10a99446123a3cc7baf5baa1eef97bc38b0b3fad..9b909432aa0edca61795c5eab91e23ec8fbd08ea 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2006-07-26 Maarten Brock <sourceforge.brock AT dse.nl>
+
+       * device/lib/_fsdiv.c,
+       * device/lib/_fsmul.c: bugfix, handle too large and too small numbers
+       * support/regression/tests/bug1520966.c: added
+
 2006-07-25 Borut Razem <borut.razem AT siol.net>
 
        * configure.in, configure, sdccconf_in.h: fixed bug
index 1768ec46a9b21c9ee3d2e5c0b29d6f833e2f3e2a..fd50c96cd6f4a539a8233a46dd374e18683c9607 100644 (file)
@@ -42,20 +42,52 @@ ___fsdiv:
        cpl     sign_a
 00001$:
 
-       // if divisor is zero, return infinity
-       cjne    r7, #0, 00002$
-       ljmp    fs_return_inf
+       // if divisor is zero, ...
+       cjne    r7, #0, 00003$
+       // if dividend is also zero, return NaN
+       cjne    r4, #0, 00002$
+       ljmp    fs_return_nan
 00002$:
+       // but dividend is non-zero, return infinity
+       ljmp    fs_return_inf
+00003$:
        // if dividend is zero, return zero
-       cjne    r4, #0, 00003$
+       cjne    r4, #0, 00004$
        ljmp    fs_return_zero
-00003$:
+00004$:
+       // if divisor is infinity, ...
+       mov     a, exp_b
+       cjne    a, #0xFF, 00006$
+       // and dividend is also infinity, return NaN
+       mov     a, exp_a
+       cjne    a, #0xFF, 00005$
+       ljmp    fs_return_nan
+00005$:
+       // but dividend is not infinity, return zero
+       ljmp    fs_return_zero
+00006$:
+       // if dividend is infinity, return infinity
+       mov     a, exp_a
+       cjne    a, #0xFF, 00007$
+       ljmp    fs_return_inf
+00007$:
 
        // subtract exponents
        clr     c
-       mov     a, exp_a
        subb    a, exp_b
+       // if no carry then no underflow
+       jnc     00008$
        add     a, #127
+       jc      00009$
+       ljmp    fs_return_zero
+
+00008$:
+       add     a, #128
+       dec     a
+       jnc     00009$
+       ljmp    fs_return_inf
+
+00009$:
        mov     exp_a, a
 
        // need extra bits on a's mantissa
@@ -67,7 +99,7 @@ ___fsdiv:
        subb    a, r3
        mov     a, r7
        subb    a, r4
-       jc      00005$
+       jc      00010$
        dec     exp_a
        clr     c
        mov     a, r2
@@ -82,15 +114,15 @@ ___fsdiv:
        clr     a
        rlc     a
        mov     r4, a
-       sjmp    00006$
-00005$:
+       sjmp    00011$
+00010$:
 #endif
        clr     a
        xch     a, r4
        xch     a, r3
        xch     a, r2
        mov     r1, a
-00006$:
+00011$:
 
        // begin long division
        push    exp_a
@@ -99,7 +131,7 @@ ___fsdiv:
 #else
        mov     b, #24
 #endif
-00010$:
+00012$:
        // compare
        clr     c
        mov     a, r1
@@ -112,11 +144,11 @@ ___fsdiv:
        subb    a, #0           // carry==0 if mant1 >= mant2
 
 #ifdef FLOAT_FULL_ACCURACY
-       djnz    b, 00011$
+       djnz    b, 00013$
        sjmp    00015$
-00011$:
+00013$:
 #endif
-       jc      00012$
+       jc      00014$
        // subtract
        mov     a, r1
        subb    a, r5
@@ -132,7 +164,7 @@ ___fsdiv:
        mov     r4, a
        clr     c
 
-00012$:
+00014$:
        // shift result
        cpl     c
        mov     a, r0
@@ -161,10 +193,10 @@ ___fsdiv:
        mov     r4, a
 
 #ifdef FLOAT_FULL_ACCURACY
-       sjmp    00010$
+       sjmp    00012$
 00015$:
 #else
-       djnz    b, 00010$
+       djnz    b, 00012$
 #endif
 
        // now we've got a division result, so all we need to do
@@ -185,6 +217,7 @@ ___fsdiv:
        pop     exp_a
        jnc     00016$
        inc     exp_a
+       // incrementing exp_a without checking carry is dangerous
        mov     r4, #0x80
 00016$:
 #else
@@ -238,7 +271,7 @@ float __fsdiv (float a1, float a2)
   volatile long result;
   volatile unsigned long mask;
   volatile long mant1, mant2;
-  volatile int exp ;
+  volatile int exp;
   char sign;
 
   fl1.f = a1;
@@ -254,8 +287,10 @@ float __fsdiv (float a1, float a2)
 
   /* divide by zero??? */
   if (!fl2.l)
-    /* return NaN or -NaN */
-    return (-1.0);
+    {/* return NaN or -NaN */
+      fl2.l = 0x7FC00000;
+      return (fl2.f);
+    }
 
   /* numerator zero??? */
   if (!fl1.l)
@@ -296,7 +331,12 @@ float __fsdiv (float a1, float a2)
   result &= ~HIDDEN;
 
   /* pack up and go home */
-  fl1.l = PACK (sign ? 1ul<<31 : 0, (unsigned long) exp, result);
+  if (exp >= 0x100)
+    fl1.l = (sign ? SIGNBIT : 0) | 0x7F800000;
+  else if (exp < 0)
+    fl1.l = 0;
+  else
+    fl1.l = PACK (sign ? SIGNBIT : 0 , exp, result);
   return (fl1.f);
 }
 
index 96be13d95c9c7267e1441972a41c89a786b82ece..553234fba0e2cfff76b14ef3f76372036341f320 100644 (file)
@@ -51,12 +51,32 @@ ___fsmul:
        cpl     sign_a
 00003$:
 
-       // add the exponents
+       // check if either input is infinity
+       mov     a, exp_b
+       cjne    a, #0xFF, 00004$
+       ljmp    fs_return_inf
+00004$:
        mov     a, exp_a
+       cjne    a, #0xFF, 00005$
+       ljmp    fs_return_inf
+00005$:
+
+       // add the exponents
        add     a, exp_b
+       // if carry then no underflow
+       jc      00006$
        add     a, #130
-       mov     exp_a, a
+       jc      00007$
+       ljmp    fs_return_zero
 
+00006$:
+       add     a, #131
+       dec     a
+       jnc     00007$
+       ljmp    fs_return_inf
+
+00007$:
+       mov     exp_a, a
 
        // now we need to multipy r4/r3/r2 * r7/r6/r5
        // ------------------------------------------
@@ -215,7 +235,7 @@ float __fsmul (float a1, float a2) {
   volatile unsigned long result;
   volatile int exp;
   char sign;
-  
+
   fl1.f = a1;
   fl2.f = a2;
 
@@ -252,7 +272,12 @@ float __fsmul (float a1, float a2) {
   result &= ~HIDDEN;
 
   /* pack up and go home */
-  fl1.l = PACK (sign ? SIGNBIT : 0 , (unsigned long)exp, result);  
+  if (exp >= 0x100)
+    fl1.l = (sign ? SIGNBIT : 0) | 0x7F800000;
+  else if (exp < 0)
+    fl1.l = 0;
+  else
+    fl1.l = PACK (sign ? SIGNBIT : 0 , exp, result);
   return (fl1.f);
 }
 
diff --git a/support/regression/tests/bug1520966.c b/support/regression/tests/bug1520966.c
new file mode 100644 (file)
index 0000000..ad125b9
--- /dev/null
@@ -0,0 +1,23 @@
+/* bug1520966 "Floating-point bug with small numbers"\r
+ */\r
+\r
+#include <testfwk.h>\r
+#include <math.h>\r
+\r
+void\r
+testFloatOp(void)\r
+{\r
+    volatile float a,b;\r
+    float result;\r
+\r
+    a = 2.04e-38;\r
+    b = 0.01;\r
+    result = a * b;\r
+    ASSERT( result < a );\r
+    ASSERT( result >= 0.0 );\r
+\r
+    b = 100;\r
+    result = a / b;\r
+    ASSERT( result < a );\r
+    ASSERT( result >= 0.0 );\r
+}\r