4

Selon le ECMAScript specification, les valeurs de nombre Javascript correspondent à une valeur IEEE 754 de format binaire 64 bits à double précision.Comment déterminer si un numéro Javascript est dans la gamme de précision simple?

Pour un validateur WebIDL sur lequel je travaille actuellement, je dois être capable de déterminer si une valeur numérique donnée peut être convertie en un type WebIDL float, c'est-à-dire si elle peut être représentée en tant que 32 bits fini simple précision Valeur IEEE 754

Je suis actuellement installé sur l'approche suivante:

validate: function(value) { 
    if (typeof value !== 'number' || !Number.isFinite(value)) { 
     return false; 
    } 

    if (value === 0) { 
     return true; 
    } 

    var view = new DataView(new ArrayBuffer(4)); 

    view.setFloat32(0, value); 

    var converted = view.getFloat32(0); 
    var relativeError = Math.abs(value - converted)/value; 

    return relativeError < Number.EPSILON; 
} 

Essentiellement, ce que je fais est:

  1. Enrouler un DataView autour d'un 4 octets ArrayBuffer.
  2. Enregistrez la valeur Number sous la forme d'un flottant de 32 bits dans le tampon.
  3. Récupère le numéro converti du tampon.
  4. Calculez l'erreur relative entre la valeur d'origine et la valeur convertie.
  5. Vérifiez si l'erreur relative est inférieure à machine epsilon pour les nombres à virgule flottante, en utilisant Number.EPSILON.

Quelques commentaires:

Est-ce que le son logique ci-dessus correspond à ce que j'essaie d'obtenir? Est-ce exagéré? Existe-t-il un moyen plus idiomatique, élégant ou performant de le faire?

Mise à jour

J'ai dans l'intervalle compris que l'approche ci-dessus est incorrecte. Il échouera pour une large gamme de valeurs telles que 1.001, 3.14159 et ainsi de suite. La modification de la valeur epsilon sur la machine epsilon pour les flottants 32 bits (2 -23) est par contre trop permissive et autorise des valeurs comme 16777217.

Toujours à la recherche d'une bonne solution, mais va actuellement avec la fonction ci-dessous qui contrôle simplement les bornes entier supérieur et inférieur (2 et - (2)).

validate: function(value) { 
    return typeof value === 'number' && Number.isFinite(value) 
      && value >= -16777216 && value <= 16777216; 
} 
+0

Vous pouvez créer un tampon et une vue 64 bits de celui-ci, puis vérifier les bits faibles. – Pointy

+0

peut 'Float32Array.from ([n]) [0]' simplifier votre routine? – dandavis

+0

@dandavis Peut-être un peu. 'Float32Array.of (n)' serait encore mieux si je descendais cette route. –

Répondre

3

Comme vous utilisez ECMAScript 6, vous pouvez utiliser Math.fround pour vérifier si elle est un numéro unique précision:

function isfloat32(x) { 
    return isNaN(x) || x == Math.fround(x); 
} 

MISE À JOUR: J'ai raté la partie sur une WebIDL float étant finie (non un Inf ou NaN).Dans ce cas,

function isfloat32(x) { 
    return isFinite(x) && x == Math.fround(x); 
}