]> www.ginac.de Git - cln.git/commitdiff
Fix a bug occurring with extremely high exponents.
authorBruno Haible <bruno@clisp.org>
Tue, 9 Mar 2004 12:52:13 +0000 (12:52 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 9 Mar 2004 12:52:13 +0000 (12:52 +0000)
ChangeLog
src/float/lfloat/algebraic/cl_LF_sqrt.cc

index e9866321e9069259bfb096633fae536ec1289b45..67dc8ba98aac5dfa742051597ea07d9c54a0cabf 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,8 @@
 
        * src/float/lfloat/elem/cl_LF_mul.cc (operator*): Fix the second
        underflow condition.
+       * src/float/lfloat/algebraic/cl_LF_sqrt.cc (sqrt): Fix a bug with large
+       uexp whereby SQRT of MOST-POSITIVE-LONG-FLOAT was less than 1.
 
 2004-03-04  Richard B. Kreckel  <kreckel@ginac.de>
 
index c551ca446fb1be7e159f670c9c9f7eb57613687c..613e4fb69eb92efda5a5fbf21ff511e9333df0e3 100644 (file)
@@ -28,7 +28,7 @@ const cl_LF sqrt (const cl_LF& x)
 //   Bei ungeradem e schiebe dies (oder nur die ersten n+1 Digits davon)
 //     um 1 Bit nach rechts.
 //   Bilde daraus die Ganzzahl-Wurzel, eine n+1-Digit-Zahl mit einer
-//     führenden 1.
+//     fhrenden 1.
 //   Runde das letzte Digit weg:
 //     Bit 15 = 0 -> abrunden,
 //     Bit 15 = 1, Rest =0 und Wurzel exakt -> round-to-even,
@@ -42,25 +42,26 @@ const cl_LF sqrt (const cl_LF& x)
       CL_ALLOCA_STACK;
       var uintD* r_MSDptr;
       var uintD* r_LSDptr;
-      var uintL r_len = 2*(uintL)len+2; // Länge des Radikanden
+      var uintL r_len = 2*(uintL)len+2; // Lge des Radikanden
       num_stack_alloc(r_len, r_MSDptr=,r_LSDptr=);
-      uexp = uexp - LF_exp_mid + 1;
-      if (uexp & bit(0))
+      if ((uexp & bit(0)) == (LF_exp_mid & bit(0)))
         // Exponent gerade
         {var uintD* ptr =
            copy_loop_msp(arrayMSDptr(TheLfloat(x)->data,len),r_MSDptr,len); // n Digits kopieren
-         clear_loop_msp(ptr,len+2); // n+2 Nulldigits anhängen
+         clear_loop_msp(ptr,len+2); // n+2 Nulldigits anhgen
         }
         else
         // Exponent ungerade
         {var uintD carry_rechts = // n Digits kopieren und um 1 Bit rechts shiften
            shiftrightcopy_loop_msp(arrayMSDptr(TheLfloat(x)->data,len),r_MSDptr,len,1,0);
          var uintD* ptr = r_MSDptr mspop len;
-         msprefnext(ptr) = carry_rechts; // Übertrag und
-         clear_loop_msp(ptr,len+1); // n+1 Nulldigits anhängen
+         msprefnext(ptr) = carry_rechts; // ertrag und
+         clear_loop_msp(ptr,len+1); // n+1 Nulldigits anhgen
         }
-      uexp = (sintL)((sintL)uexp >> 1); // Exponent halbieren
-      uexp = uexp + LF_exp_mid;
+      // Compute ((uexp - LF_exp_mid + 1) >> 1) + LF_exp_mid without risking
+      // uintL overflow.
+      uexp = ((uexp - ((LF_exp_mid - 1) & 1)) >> 1) - ((LF_exp_mid - 1) >> 1)
+             + LF_exp_mid;
       // Ergebnis allozieren:
       var Lfloat y = allocate_lfloat(len,uexp,0);
       var uintD* y_mantMSDptr = arrayMSDptr(TheLfloat(y)->data,len);
@@ -80,7 +81,7 @@ const cl_LF sqrt (const cl_LF& x)
           // Ablegen und runden:
           copy_loop_msp(p_MSDptr mspop 1,y_mantMSDptr,len); // NUDS nach y kopieren
           if (mspref(p_MSDptr,0) == 0)
-            { if ( ((sintD)mspref(p_MSDptr,len+1) >= 0) // nächstes Bit =0 -> abrunden
+            { if ( ((sintD)mspref(p_MSDptr,len+1) >= 0) // nhstes Bit =0 -> abrunden
                    || ( ((mspref(p_MSDptr,len+1) & ((uintD)bit(intDsize-1)-1)) ==0) // =1 und weitere Bits >0 -> aufrunden
                         && !test_loop_msp(p_MSDptr mspop (len+2),len+1)
                         // round-to-even (etwas witzlos, da eh alles ungenau ist)
@@ -91,13 +92,13 @@ const cl_LF sqrt (const cl_LF& x)
                 else
                 // aufrunden
                 { if ( inc_loop_lsp(y_mantMSDptr mspop len,len) )
-                    // Übertrag durchs Aufrunden
+                    // ertrag durchs Aufrunden
                     { mspref(y_mantMSDptr,0) = bit(intDsize-1); // Mantisse := 10...0
                       (TheLfloat(y)->expo)++; // Exponenten incrementieren
                 }   }
             }
             else
-            // Übertrag durch Rundungsfehler
+            // ertrag durch Rundungsfehler
             { if (test_loop_msp(y_mantMSDptr,len)) cl_abort();
               mspref(y_mantMSDptr,0) = bit(intDsize-1); // Mantisse := 10...0
               (TheLfloat(y)->expo)++; // Exponenten incrementieren
@@ -111,7 +112,7 @@ const cl_LF sqrt (const cl_LF& x)
       // w ist die Ganzzahl-Wurzel, eine n+1-Digit-Zahl.
       copy_loop_msp(w.MSDptr,y_mantMSDptr,len); // NUDS nach y kopieren
       // Runden:
-      if ( ((sintD)lspref(w.LSDptr,0) >= 0) // nächstes Bit =0 -> abrunden
+      if ( ((sintD)lspref(w.LSDptr,0) >= 0) // nhstes Bit =0 -> abrunden
            || ( ((lspref(w.LSDptr,0) & ((uintD)bit(intDsize-1)-1)) ==0) // =1 und weitere Bits >0 oder Rest >0 -> aufrunden
                 && exactp
                 // round-to-even
@@ -122,7 +123,7 @@ const cl_LF sqrt (const cl_LF& x)
         else
         // aufrunden
         { if ( inc_loop_lsp(y_mantMSDptr mspop len,len) )
-            // Übertrag durchs Aufrunden
+            // ertrag durchs Aufrunden
             { mspref(y_mantMSDptr,0) = bit(intDsize-1); // Mantisse := 10...0
               (TheLfloat(y)->expo)++; // Exponenten incrementieren
         }   }