我将是第一个承认我对底层编程的总体知识很少的人。我了解许多核心概念,但我不会定期使用它们。
话虽如此,我对dtoa.c需要多少代码感到非常惊讶。
在过去的几个月中,我一直在使用C#进行ECMAScript实现,并且一直在缓慢填充引擎中的漏洞。昨晚我开始研究ECMAScript specification (pdf)的 15.7.4.2 部分,介绍了 Number.prototype.toString 。在 9.8.1 部分中,NOTE 3提供了指向dtoa.c的链接,但是我一直在寻找挑战,因此我等待查看。以下是我想出的。
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());
}
具有低级编程经验的任何人都可以解释dtoa.c为什么具有大约40倍的代码吗?我只是无法想象C#会提高生产力。
最佳答案
dtoa.c包含两个主要功能:dtoa(),它将 double 型转换为字符串,以及strtod(),将字符串转换为 double 型。它还包含许多支持功能,其中大多数功能都是针对其自己的任意精度算术实现。 dtoa.c声名claim起的是正确完成了这些转换,并且通常只能使用任意精度算术来完成。它还具有在四种不同的舍入模式下正确舍入转换的代码。
您的代码仅尝试实现dtoa()的等效项,并且由于它使用浮点数进行转换,因此不一定总是正确。 (更新:有关详细信息,请参见我的文章http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal-conversion/。)
(我在博客http://www.exploringbinary.com/上写了很多有关此内容的文章。最近七篇文章中有六篇仅涉及strtod()转换。通读它们以了解正确进行四舍五入转换的复杂性。)
关于c# - 为什么 “dtoa.c”包含这么多代码?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3173056/