Pourquoi "dtoa"?c" contiennent tellement de code?

je serai le premier à admettre que ma connaissance globale de la programmation de bas niveau est un peu faible. Je comprends bon nombre des concepts de base, mais je ne les utilise pas régulièrement. Cela étant dit, j'ai été absolument stupéfait de voir combien de code était nécessaire pour dtoa.c .

au cours des derniers mois, j'ai travaillé sur une implémentation D'ECMAScript en C# et j'ai ralenti à combler les trous dans mon moteur. La nuit dernière j'ai commencé à travailler sur le numéro .prototype.toString qui est décrit dans la section 15.7.4.2 de la spécification ECMAScript (pdf) . Dans la section 9.8.1 , la NOTE 3 offre un lien vers dtoa.c mais je cherchais un défi alors j'ai attendu pour le voir. La suivante est ce que je suis venu avec.

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());
}

n'importe quelle personne avec plus d'expérience dans le bas la programmation de niveau explique pourquoi dtoa.c a environ 40 fois plus de code? Je ne peux pas imaginer que C# soit plus productif.

18
demandé sur Krinkle 2010-07-04 02:30:31

5 réponses

dtoa.c contient deux fonctions principales: dtoa(), qui convertit une double chaîne, et strtod(), qui convertit une chaîne en un double. Il contient également beaucoup de fonctions de soutien, dont la plupart sont pour sa propre mise en œuvre de l'arithmétique de précision arbitraire. dtoa.la prétention de c à la gloire est d'obtenir ces conversions droite, et cela ne peut être fait, en général, avec l'arithmétique de précision arbitraire. Il a également le code pour arrondir les conversions correctement dans quatre modes d'arrondi différents.

votre code essaie seulement d'implémenter l'équivalent de dtoa(), et puisqu'il utilise le flottant-point pour faire ses conversions, il ne les obtiendra pas toujours correctement. (Mise à jour: Voir mon article http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal-conversion / for details.)

(j'ai beaucoup écrit à ce sujet sur mon blog, http://www.exploringbinary.com / . Six de mes sept derniers articles portaient sur strtod.() les conversions seules. Lisez - les pour voir à quel point il est compliqué de faire des conversions correctement arrondies.)

38
répondu Rick Regan 2010-11-12 18:37:41

Produire bon des résultats pour les conversions entre décimal et binaire à virgule flottante représentation est assez difficile problème.

la principale source de difficulté est que de nombreuses fractions décimales, même simples, ne peuvent pas être avec précision exprimées en utilisant la virgule flottante binaire -- par exemple, 0.5 peut (évidemment), mais 0.1 ne peut pas. Et, dans l'autre sens (de binaire en décimal), vous généralement ne veulent pas le résultat absolument précis (par exemple, la valeur décimale exacte du nombre le plus proche de 0.1 qui peut être représenté dans un IEEE-754 conforme double est en fait 0.1000000000000000055511151231257827021181583404541015625 ) donc vous voulez normalement un peu d'arrondissement.

ainsi, la conversion implique souvent une approximation. Bonne conversion routines garantie pour produire le le plus proche approximation possible à l'intérieur de particulier (Taille du mot ou le nombre de chiffres) contraintes. C'est où la plupart de la complexité vient de.

jetez un coup d'oeil à l'Article cité dans les commentaires au début de la dtoa.c mise en œuvre, Clinger's Comment lire les nombres à virgule flottante avec précision , pour une flaveur du problème; et peut-être David M. Gay (l'auteur)'s Papier, correctement arrondis binaire-décimal Et décimal-binaire Conversions .

(aussi, plus généralement: Ce Que Tout Informaticien Devriez Savoir Sur L'Arithmétique À Virgule Flottante .)

7
répondu Matthew Slattery 2012-06-27 20:38:59

basé sur un coup d'oeil rapide, une bonne partie de la version C traite de plates-formes multiples et comme il semble que ce fichier est destiné à être généreusement Utilisable à travers des compilateurs (C & C++), des bitnesses, des implémentations de point flottant, et des plates-formes; avec des tonnes de #define configurabilité.

4
répondu dkackman 2010-07-03 22:41:25

je pense aussi que le code dans dtoa.c pourrait être plus efficace (indépendamment de la langue). Par exemple, il semble faire un peu de bricolage, qui dans les mains d'un expert signifie souvent la vitesse. Je suppose qu'il utilise simplement un algorithme moins intuitif pour des raisons de vitesse.

4
répondu Lajnold 2010-07-03 23:10:46

courte réponse: parce que dtoa.c fonctionne.

C'est exactement la différence entre un produit bien débogué et un prototype NIH.

2
répondu Pavel Radzivilovsky 2010-07-04 19:21:52