Răsfoiți Sursa

Fix IEEE754 compatibility issues

Oguz Bastemur 9 ani în urmă
părinte
comite
88fdcc5b59

+ 24 - 10
lib/Common/Common/NumberUtilities_strtod.cpp

@@ -1263,7 +1263,7 @@ template double Js::NumberUtilities::StrToDbl<utf8char_t>(const utf8char_t * psz
 Uses big integer arithmetic to get the sequence of digits.
 ***************************************************************************/
 _Success_(return)
-static BOOL FDblToRgbPrecise(double dbl, __out_ecount(kcbMaxRgb) byte *prgb, int *pwExp10, byte **ppbLim)
+static BOOL FDblToRgbPrecise(double dbl, __out_ecount(kcbMaxRgb) byte *prgb, int *pwExp10, byte **ppbLim, int normalizeHBound = 1)
 {
     byte bT;
     BOOL fPow2;
@@ -1516,7 +1516,9 @@ static BOOL FDblToRgbPrecise(double dbl, __out_ecount(kcbMaxRgb) byte *prgb, int
             if (bT != 9)
             {
                 Assert(ib < kcbMaxRgb);
-                prgb[ib++] = bT + 1;
+                // Do not always push to higherBound
+                // See Js::NumberUtilities::FDblToStr for the exception
+                prgb[ib++] = bT + (byte)normalizeHBound;
                 break;
             }
 LRoundUp9:
@@ -1562,7 +1564,8 @@ LFail:
 Get mantissa bytes (BCD).
 ***************************************************************************/
 _Success_(return)
-static BOOL FDblToRgbFast(double dbl, _Out_writes_to_(kcbMaxRgb, (*ppbLim - prgb)) byte *prgb, int *pwExp10, byte **ppbLim)
+static BOOL FDblToRgbFast(double dbl, _Out_writes_to_(kcbMaxRgb, (*ppbLim - prgb)) byte *prgb,
+                          int *pwExp10, byte **ppbLim, const int highBound = 1)
 {
     int ib;
     int iT;
@@ -1808,7 +1811,16 @@ static BOOL FDblToRgbFast(double dbl, _Out_writes_to_(kcbMaxRgb, (*ppbLim - prgb
         // the difference.
         prgb[ib++] = (bHL + bLH + 1) / 2;
     }
-    else if (0 != luHL || !numHL.FZero() || 0 == (Js::NumberUtilities::LuLoDbl(dbl) & 1))
+    // We don't know whether BHL or BLH is the correct one
+    // When highBound is set, that means the consumer is not
+    // interested with the entire value. On the other hand, we may not
+    // just roundup to the higher bound. That breaks IEEE754
+    // Imagine LowerBound is 4999... while the UpperBoud is 50001..
+    // We need to know where actually the number is instead of picking
+    // either Lower or UpperBoud
+    // at this point, we should skip and fail
+    // let FDblToRgbPrecise do the math.
+    else if (highBound == 1 && (0 != luHL || !numHL.FZero() || 0 == (Js::NumberUtilities::LuLoDbl(dbl) & 1)))
     {
         Assert(ib < kcbMaxRgb);
         if(!(ib < kcbMaxRgb))
@@ -2199,7 +2211,7 @@ static int RoundTo(byte *pbSrc, byte *pbLim, int nDigits, __out_bcount(nDigits+1
     {
         int i = nDigits;
 
-        if( pbSrc[i] > 5 )
+        if( pbSrc[i] >= 5 )
         {
             // Add 1 to the BCD representation.
             for( i = nDigits - 1; i >= 0; i-- )
@@ -2241,6 +2253,7 @@ static int RoundTo(byte *pbSrc, byte *pbLim, int nDigits, __out_bcount(nDigits+1
 * Returns the number of chars. in the result. If 'nDstBufSize'
 * is less than this number, no data is written to the buffer 'pchDst'.
 */
+
 int Js::NumberUtilities::FDblToStr(double dbl, Js::NumberUtilities::FormatType ft, int nDigits, __out_ecount(cchDst) char16 *pchDst, int cchDst)
 {
     int n = 0; // the no. of chars in the result.
@@ -2286,7 +2299,7 @@ int Js::NumberUtilities::FDblToStr(double dbl, Js::NumberUtilities::FormatType f
         if (Js::NumberUtilities::LuHiDbl(dbl) & 0x80000000)
         {
             n++;
-            if( cchDst >= n)
+            if(cchDst >= n)
             {
                 *pchDst++ = '-';
                 cchDst--;
@@ -2294,13 +2307,14 @@ int Js::NumberUtilities::FDblToStr(double dbl, Js::NumberUtilities::FormatType f
             Js::NumberUtilities::LuHiDbl(dbl) &= 0x7FFFFFFF;
         }
 
-        if (!FDblToRgbFast(dbl, rgb, &wExp10, &pbLim) &&
-            !FDblToRgbPrecise(dbl, rgb, &wExp10, &pbLim))
+        const int hBound = nDigits == -1 ? 1 : 0;
+        // in case we restrict the number of digits, do not push for a higher bound
+        if (!FDblToRgbFast(dbl, rgb, &wExp10, &pbLim, hBound) &&
+            !FDblToRgbPrecise(dbl, rgb, &wExp10, &pbLim, hBound))
         {
             AssertMsg(FALSE, "Failure in FDblToRgbPrecise");
             return FALSE;
         }
-
     }
 
     // We have to round up and truncate the BCD representation of the mantissa
@@ -2322,7 +2336,7 @@ int Js::NumberUtilities::FDblToStr(double dbl, Js::NumberUtilities::FormatType f
             else
             {
                 //Special case: When negative power of 10 is more than most significant digit.
-                if( rgb[0] > 5 )
+                if( rgb[0] >= 5 )
                 {
                     rgbAdj[0] = 1;
                     wExp10 += 1;

+ 0 - 1
test/Array/nativeFloatArray_sort.js

@@ -13,4 +13,3 @@ function Test()
 }
 
 Test();
-

+ 4 - 2
test/Number/toString.js

@@ -41,8 +41,10 @@ function runTest(numberToTestAsString)
 
     // test toFixed toString round formatting
     if ( !(1.25499999999999989342.toFixed(2) + "" == "1.25") ||
-         !(1.255.toFixed(2) + "" == "1.25") ) {
-        throw Error("1.255.toFixed(2) != 1.25 ??");
+         !(1.255.toFixed(2) + "" == "1.25") ||
+         !(1.245.toFixed(2) + "" == "1.25") ||
+         !(8.255.toFixed(2) + "" == "8.26") ) {
+        throw Error("1.255.toFixed(2) != 1.25 or 8.255.toFixed(2) != 8.26 ??");
     }
     writeLine("");
 }