tipos primitivos float español decimales datos c# javascript c floating-point ecma262

c# - primitivos - parseint javascript



¿Por qué “dtoa.c” contiene tanto código? (5)

Basándonos en un vistazo rápido, una buena cantidad de la versión C trata con múltiples plataformas y, por lo que parece, este archivo está destinado a ser genéricamente utilizable en compiladores (C y C ++), bitnesses, implementaciones de punto flotante y plataformas ; Con toneladas de configurabilidad #define .

Seré el primero en admitir que mi conocimiento general de la programación de bajo nivel es un poco escaso. Entiendo muchos de los conceptos básicos, pero no los uso de forma regular. Dicho esto, estaba absolutamente asombrado de la cantidad de código necesario para dtoa.c

Durante los últimos dos meses he estado trabajando en una implementación de ECMAScript en C # y he estado ralentizando los agujeros en mi motor. Anoche comencé a trabajar en Number.prototype.toString, que se describe en la sección 15.7.4.2 de la especificación ECMAScript (pdf) . En la sección 9.8.1 , la NOTA 3 ofrece un enlace a dtoa.c, pero estaba buscando un desafío, así que esperé para verlo. Lo siguiente es lo que se me ocurrió.

private IDynamic ToString(Engine engine, Args args) { var thisBinding = engine.Context.ThisBinding; if (!(thisBinding is NumberObject) && !(thisBinding is NumberPrimitive)) { throw RuntimeError.TypeError("The current ''this'' must be a number or a number object."); } var num = thisBinding.ToNumberPrimitive(); if (double.IsNaN(num)) { return new StringPrimitive("NaN"); } else if (double.IsPositiveInfinity(num)) { return new StringPrimitive("Infinity"); } else if (double.IsNegativeInfinity(num)) { return new StringPrimitive("-Infinity"); } var radix = !args[0].IsUndefined ? args[0].ToNumberPrimitive().Value : 10D; if (radix < 2D || radix > 36D) { throw RuntimeError.RangeError("The parameter [radix] must be between 2 and 36."); } else if (radix == 10D) { return num.ToStringPrimitive(); } var sb = new StringBuilder(); var isNegative = false; if (num < 0D) { isNegative = true; num = -num; } var integralPart = Math.Truncate(num); var decimalPart = (double)((decimal)num.Value - (decimal)integralPart); var radixChars = RadixMap.GetArray((int)radix); if (integralPart == 0D) { sb.Append(''0''); } else { var integralTemp = integralPart; while (integralTemp > 0) { sb.Append(radixChars[(int)(integralTemp % radix)]); integralTemp = Math.Truncate(integralTemp / radix); } } var count = sb.Length - 1; for (int i = 0; i < count; i++) { var k = count - i; var swap = sb[i]; sb[i] = sb[k]; sb[k] = swap; } if (isNegative) { sb.Insert(0, ''-''); } if (decimalPart == 0D) { return new StringPrimitive(sb.ToString()); } var runningValue = 0D; var decimalIndex = 1D; var decimalTemp = decimalPart; sb.Append(''.''); while (decimalIndex < 100 && decimalPart - runningValue > 1.0e-50) { var result = decimalTemp * radix; var integralResult = Math.Truncate(result); runningValue += integralResult / Math.Pow(radix, decimalIndex++); decimalTemp = result - integralResult; sb.Append(radixChars[(int)integralResult]); } return new StringPrimitive(sb.ToString()); }

¿Puede alguien con más experiencia en programación de bajo nivel explicar por qué dtoa.c tiene aproximadamente 40 veces más código? Simplemente no puedo imaginar que C # sea mucho más productivo.


Producir buenos resultados para las conversiones entre decimales y representaciones binarias de punto flotante es un problema bastante difícil.

La principal fuente de dificultad es que muchas fracciones decimales, incluso las simples, no pueden expresarse con precisión utilizando un punto flotante binario; por ejemplo, 0.5 puede (obviamente), pero 0.1 no. Y, yendo a la inversa (de binario a decimal), generalmente no querrá un resultado absolutamente preciso (por ejemplo, el valor decimal exacto del número más cercano a 0.1 que se puede representar en un double compatible con IEEE-754 es en realidad, 0.1000000000000000055511151231257827021181583404541015625 ) por lo que normalmente desea un poco de redondeo.

Por lo tanto, la conversión a menudo implica aproximación. Las buenas rutinas de conversión garantizan producir la aproximación más cercana posible dentro de restricciones particulares (tamaño de palabra o número de dígitos). De aquí proviene la mayor parte de la complejidad.

Eche un vistazo al documento citado en el comentario en la parte superior de la implementación de dtoa.c , los números de punto flotante de Clinger con precisión , para conocer el problema; y quizás el documento de David M. Gay (el autor), Conversiones redondeadas binario-decimales y decimales-binarias correctamente redondeadas .

(Además, de manera más general: lo que todo científico informático debe saber sobre la aritmética de punto flotante ).


Respuesta corta: porque dtoa.c funciona.

Esta es exactamente la diferencia entre un producto bien depurado y un prototipo de NIH.


También creo que el código en dtoa.c podría ser más eficiente (independiente del idioma). Por ejemplo, parece que se está haciendo un poco de manipulación de bits, que en manos de un experto a menudo significa velocidad. Supongo que simplemente utiliza un algoritmo menos intuitivo por razones de velocidad.


dtoa.c contiene dos funciones principales: dtoa (), que convierte un doble en una cadena, y strtod (), que convierte una cadena en un doble. También contiene muchas funciones de soporte, la mayoría de las cuales son para su propia implementación de aritmética de precisión arbitraria. La afirmación de dtoa.c a la fama es hacer estas conversiones correctamente, y eso solo se puede hacer, en general, con aritmética de precisión arbitraria. También tiene código para redondear las conversiones correctamente en cuatro modos de redondeo diferentes.

Su código solo intenta implementar el equivalente de dtoa (), y dado que usa el punto flotante para hacer sus conversiones, no siempre los hará bien. (Actualización: consulte mi artículo http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal-conversion/ para obtener más información).

(He escrito mucho sobre esto en mi blog, http://www.exploringbinary.com/ . Seis de mis últimos siete artículos han sido sobre conversiones de strtod () solo. Léalos para ver qué tan complicado es hacerlo. conversiones correctamente redondeadas.)