我将是第一个承认我对底层编程的总体知识很少的人。我了解许多核心概念,但我不会定期使用它们。
话虽如此,我对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/

10-11 11:27