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'; } }
// // Convert a Number to a double. // internal static bool NumberBufferToDouble(ref NumberBuffer number, out double value) { double d = NumberToDouble(ref number); if (!Double.IsFinite(d)) { value = default; return(false); } if (d == 0.0) { // normalize -0.0 to 0.0 d = 0.0; } value = d; return(true); }
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]++; } }