private static unsafe void DoubleToNumber(double value, int precision, ref NumberBuffer number) { number.precision = precision; if (!Double.IsFinite(value)) { number.scale = Double.IsNaN(value) ? ScaleNAN : ScaleINF; number.sign = Double.IsNegative(value); number.digits[0] = '\0'; } else { byte *src = stackalloc byte[_CVTBUFSIZE]; int sign; fixed(NumberBuffer *pNumber = &number) { RuntimeImports._ecvt_s(src, _CVTBUFSIZE, value, precision, &pNumber->scale, &sign); } number.sign = sign != 0; char *dst = number.digits; if ((char)*src != '0') { while (*src != 0) { *dst++ = (char)*src++; } } *dst = '\0'; } }
public static double Round(double a) { // If the number has no fractional part do nothing // This shortcut is necessary to workaround precision loss in borderline cases on some platforms if (a == (double)(Int64)a) { return(a); } double tempVal = a + 0.5; // We had a number that was equally close to 2 integers. // We need to return the even one. double flrTempVal = RuntimeImports.floor(tempVal); if (flrTempVal == tempVal) { if (0.0 != RuntimeImports.fmod(tempVal, 2.0)) { flrTempVal -= 1.0; } } if (flrTempVal == 0 && Double.IsNegative(a)) { flrTempVal = Double.NegativeZero; } return(flrTempVal); }
public static double IEEERemainder(double x, double y) { if (Double.IsNaN(x)) { return(x); // IEEE 754-2008: NaN payload must be preserved } if (Double.IsNaN(y)) { return(y); // IEEE 754-2008: NaN payload must be preserved } double regularMod = x % y; if (Double.IsNaN(regularMod)) { return(Double.NaN); } if (regularMod == 0) { if (Double.IsNegative(x)) { return(Double.NegativeZero); } } double alternativeResult; alternativeResult = regularMod - (Math.Abs(y) * Math.Sign(x)); if (Math.Abs(alternativeResult) == Math.Abs(regularMod)) { double divisionResult = x / y; double roundedResult = Math.Round(divisionResult); if (Math.Abs(roundedResult) > Math.Abs(divisionResult)) { return(alternativeResult); } else { return(regularMod); } } if (Math.Abs(alternativeResult) < Math.Abs(regularMod)) { return(alternativeResult); } else { return(regularMod); } }
private static unsafe void DoubleToNumber(double value, int precision, ref NumberBuffer number) { Debug.Assert(precision > 0 && precision < 40); number.precision = precision; if (!Double.IsFinite(value)) { number.scale = Double.IsNaN(value) ? ScaleNAN : ScaleINF; number.sign = Double.IsNegative(value); number.digits[0] = '\0'; return; } byte *tempBuffer = stackalloc byte[MAX_BUFFER_SIZE]; char *dst = number.digits; number.scale = 0; number.sign = double.IsNegative(value); *dst = '\0'; if (value == 0.0) { for (int j = 0; j < precision; j++) { dst[j] = '0'; } dst[precision] = '\0'; return; } // // Get the number formatted as a string in the form x.xxxxxxexxxx // // "%.40e" byte *format = stackalloc byte[6]; format[0] = (byte)'%'; format[1] = (byte)'.'; format[2] = (byte)'4'; format[3] = (byte)'0'; format[4] = (byte)'e'; format[5] = 0; int tempBufferLength = Interop.Sys.DoubleToString(value, format, tempBuffer, MAX_BUFFER_SIZE); Debug.Assert(tempBufferLength > 0 && MAX_BUFFER_SIZE > tempBufferLength); // // Calculate the exponent value // int exponentIndex = tempBufferLength - 1; while (tempBuffer[exponentIndex] != (byte)'e' && exponentIndex > 0) { exponentIndex--; } Debug.Assert(exponentIndex > 0 && (exponentIndex < tempBufferLength - 1)); int i = exponentIndex + 1; int exponentSign = 1; if (tempBuffer[i] == '-') { exponentSign = -1; i++; } else if (tempBuffer[i] == '+') { i++; } int exponentValue = 0; while (i < tempBufferLength) { Debug.Assert(tempBuffer[i] >= (byte)'0' && tempBuffer[i] <= (byte)'9'); exponentValue = exponentValue * 10 + (tempBuffer[i] - (byte)'0'); i++; } exponentValue *= exponentSign; // // Determine decimal location. // if (exponentValue == 0) { number.scale = 1; } else { number.scale = exponentValue + 1; } // // Copy the string from the temp buffer upto precision characters, removing the sign, and decimal as required. // i = 0; int mantissaIndex = 0; while (i < precision && mantissaIndex < exponentIndex) { if (tempBuffer[mantissaIndex] >= (byte)'0' && tempBuffer[mantissaIndex] <= (byte)'9') { dst[i] = (char)tempBuffer[mantissaIndex]; i++; } mantissaIndex++; } while (i < precision) { dst[i] = '0'; // append zeros as needed i++; } dst[i] = '\0'; // // Round if needed // if (mantissaIndex >= exponentIndex || tempBuffer[mantissaIndex] < (byte)'5') { return; // rounding is not needed } i = precision - 1; while (dst[i] == '9' && i > 0) { dst[i] = '0'; i--; } if (i == 0 && dst[i] == '9') { dst[i] = '1'; number.scale++; } else { dst[i]++; } }