web-dev-qa-db-fra.com

Comment obtenir les décimales d'un nombre à virgule flottante en Javascript?

Ce que j'aimerais avoir, c'est presque le contraire de Number.prototype.toPrecision (), ce qui signifie que quand j'ai un nombre, combien de décimales y a-t-il? Par exemple.

(12.3456).getDecimals() // 4
22
JussiR

Pour ceux qui se demandent comment faire cela plus rapidement (sans convertir en chaîne), voici une solution:

function precision(a) {
  var e = 1;
  while (Math.round(a * e) / e !== a) e *= 10;
  return Math.log(e) / Math.LN10;
}

Edit: une solution plus complète avec les cas Edge couverts:

function precision(a) {
  if (!isFinite(a)) return 0;
  var e = 1, p = 0;
  while (Math.round(a * e) / e !== a) { e *= 10; p++; }
  return p;
}
35
Mourner

Une solution possible (dépend de l'application):

var precision = (12.3456 + "").split(".")[1].length;
21
Manish

Si par "précision" vous voulez dire "décimales", c'est impossible, car les flottants sont binaires . Ils n'ont pas ont décimales, et la plupart des valeurs comportant un petit nombre de décimales ont des chiffres récurrents en binaire, et lorsqu'elles sont converties en décimales, elles ne donnent pas nécessairement le nombre décimal d'origine. .

Tout code fonctionnant avec les "décimales" d'un flottant est susceptible de produire des résultats inattendus sur certains nombres.

3

Basé sur la méthode de @ boolean_Type pour gérer les exposants, mais en évitant les expressions rationnelles:

function getPrecision (value) {
    if (!isFinite(value)) { return 0; }

    const [int, float = ''] = Number(value).toFixed(12).split('.');

    let precision = float.length;
    while (float[precision - 1] === '0' && precision >= 0) precision--;

    return precision;
}
1
Sc0ttyD

Essayez ce qui suit 

function countDecimalPlaces(number) { 
  var str = "" + number;
  var index = str.indexOf('.');
  if (index >= 0) {
    return str.length - index - 1;
  } else {
    return 0;
  }
}
1
JaredPar

Il n'y a pas de fonction native pour déterminer le nombre de décimales. Ce que vous pouvez faire est de convertir le nombre en chaîne, puis de compter le décalage sur le délimiteur décimal .:

Number.prototype.getPrecision = function() {
    var s = this + "",
        d = s.indexOf('.') + 1;

    return !d ? 0 : s.length - d;
};

(123).getPrecision() === 0;
(123.0).getPrecision() === 0;
(123.12345).getPrecision() === 5;
(1e3).getPrecision() === 0;
(1e-3).getPrecision() === 3;

Mais il est dans la nature des flotteurs de vous tromper. 1 peut aussi bien être représenté par 0.00000000989 ou quelque chose d'autre. Je ne suis pas sûr de la performance réelle de ce qui précède dans les applications réelles.

1
rodneyrehm

En vous basant sur le commentaire @ blackpla9ue et en considérant le format exponentiel des nombres:

function getPrecision (num) {
  var numAsStr = num.toFixed(10); //number can be presented in exponential format, avoid it
  numAsStr = numAsStr.replace(/0+$/g, '');

  var precision = String(numAsStr).replace('.', '').length - num.toFixed().length;
  return precision;  
}

getPrecision(12.3456);         //4
getPrecision(120.30003300000); //6, trailing zeros are truncated
getPrecision(15);              //0
getPrecision(120.000))         //0
getPrecision(0.0000005);       //7
getPrecision(-0.01))           //2
1
Boolean_Type

Voici quelques exemples, un qui utilise une bibliothèque ( BigNumber.js ) et un autre qui n’utilise pas de bibliothèque. Supposons que vous souhaitiez vérifier qu'un nombre saisi (inputNumber) possède un nombre de décimales inférieur ou égal à un nombre maximal de décimales (tokenDecimals).

Avec BigNumber.js

import BigNumber from 'bignumber.js'; // ES6
// const BigNumber = require('bignumber.js').default; // CommonJS

const tokenDecimals = 18;
const inputNumber = 0.000000000000000001;
// Convert to BigNumber
const inputNumberBn = new BigNumber(inputNumber);

// BigNumber.js API Docs: http://mikemcl.github.io/bignumber.js/#dp
console.log(`Invalid?: ${inputNumberBn.dp() > tokenDecimals}`);

Sans BigNumber.js

function getPrecision(numberAsString) {
  var n = numberAsString.toString().split('.');
  return n.length > 1
    ? n[1].length
    : 0;
}

const tokenDecimals = 18;
const inputNumber = 0.000000000000000001;

// Conversion of number to string returns scientific conversion
// So obtain the decimal places from the scientific notation value
const inputNumberDecimalPlaces = inputNumber.toString().split('-')[1];

// Use `toFixed` to convert the number to a string without it being
// in scientific notation and with the correct number decimal places
const inputNumberAsString = inputNumber.toFixed(inputNumberDecimalPlaces);

// Check if inputNumber is invalid due to having more decimal places
// than the permitted decimal places of the token
console.log(`Invalid?: ${getPrecision(inputNumberAsString) > tokenDecimals}`);
0
Luke Schoen

Les approches suivantes fonctionnent-elles?

var num = 12.3456
console.log(num - Math.floor(num))

ou 

console.log(num - parseInt(num))
0
Enayat Rajabi