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:
- Enrouler un
DataView
autour d'un 4 octetsArrayBuffer
. - Enregistrez la valeur
Number
sous la forme d'un flottant de 32 bits dans le tampon. - Récupère le numéro converti du tampon.
- Calculez l'erreur relative entre la valeur d'origine et la valeur convertie.
- Vérifiez si l'erreur relative est inférieure à machine epsilon pour les nombres à virgule flottante, en utilisant
Number.EPSILON
.
Quelques commentaires:
- J'application de la présente dans le cadre d'une extension Chrome, la compatibilité du navigateur est pas vraiment un problème.
- Oui, j'ai lu What Every Computer Scientist Should Know About Floating-Point Arithmetic. Mes yeux doivent encore arrêter de saigner.
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;
}
Vous pouvez créer un tampon et une vue 64 bits de celui-ci, puis vérifier les bits faibles. – Pointy
peut 'Float32Array.from ([n]) [0]' simplifier votre routine? – dandavis
@dandavis Peut-être un peu. 'Float32Array.of (n)' serait encore mieux si je descendais cette route. –