Question

Je serai le premier à admettre que ma connaissance globale de programmation de bas niveau est un peu clairsemée. Je comprends beaucoup des concepts de base, mais je ne les utilise pas sur une base régulière. Cela étant dit, je suis absolument étonné combien de code était nécessaire pour dtoa.c.

Pour les deux derniers mois, je travaille sur une mise en œuvre ECMAScript en C # et j'ai connu un ralentissement de remplissage dans les trous dans mon moteur. La nuit dernière, je commence à travailler sur Number.prototype.toString qui est décrit dans la section 15.7.4.2 spécification ECMAScript (pdf) . Dans la section 9.8.1 , NOTE 3 offres un lien vers dtoa.c mais je cherchais un défi alors j'ai attendu pour la voir. Ce qui suit 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());
}

Quelqu'un peut-il avec plus d'expérience dans la programmation de bas niveau expliquer pourquoi dtoa.c a environ 40 fois plus beaucoup de code? Je ne peux pas imaginer C # être beaucoup plus productifs.

Était-ce utile?

La solution

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

Votre code essaie seulement de mettre en œuvre l'équivalent de dtoa (), et étant donné qu'il utilise en virgule flottante pour faire ses conversions, ne sera pas toujours les obtenir droit. (Mise à jour: voir mon article http: // www. exploringbinary.com/quick-and-dirty-floating-point-to-decimal-conversion/ pour plus de détails.)

(je l'ai écrit beaucoup à ce sujet sur mon blog, http://www.exploringbinary.com/. Six de mes sept derniers articles ont été sur les conversions strtod () seul. Lisez-les pour voir comment il est compliqué de faire des conversions correctement arrondies.)

Autres conseils

Producing bon résultats pour les conversions entre les décimales et les représentations à virgule flottante binaire est un problème assez difficile.

La principale source de difficulté est que de nombreuses fractions décimales, même simples, ne peuvent pas être avec précision exprimée en virgule flottante sont binaires - par exemple, 0.5 peut (évidemment), mais 0.1 ne peut pas. Et l'autre sens (de binaire en décimal), vous ne voulez pas généralement le résultat tout à fait exact (par exemple, la valeur décimale précise du nombre le plus proche de 0.1 qui peut être représenté dans un IEEE-754 conforme double est réellement 0.1000000000000000055511151231257827021181583404541015625) de sorte que vous voulez normalement un peu arrondi.

Ainsi, la conversion implique souvent approximation. Les bonnes routines de conversion garantissent pour produire le le plus proche approximation possible dans des contraintes particulières (taille de mot ou le nombre de chiffres). C'est là la majeure partie de la complexité vient.

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

(En outre, plus généralement: Ce que tout informaticien doit- savoir sur Floating point arithmétique.)

D'après un rapide coup d'œil à elle, un montant équitable de la version C traite avec de multiples plates-formes et tel qu'il ressemble à ce fichier est destiné à être génériquement utilisables dans les compilateurs (C & C ++), bitnesses, flottante implémentations de point et plates-formes; avec des tonnes de #define configurabilité.

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

Réponse courte:. Parce que les travaux de dtoa.c

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top