How do I get the decimal places of a floating point number in Javascript?

41,632

Solution 1

For anyone wondering how to do this faster (without converting to string), here's a solution:

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

Edit: a more complete solution with edge cases covered:

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

Solution 2

One possible solution (depends on the application):

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

Solution 3

If by "precision" you mean "decimal places", then that's impossible because floats are binary. They don't have decimal places, and most values that have a small number of decimal places have recurring digits in binary, and when they're translated back to decimal that doesn't necessarily yield the original decimal number.

Any code that works with the "decimal places" of a float is liable to produce unexpected results on some numbers.

Solution 4

There is no native function to determine the number of decimals. What you can do is convert the number to string and then count the offset off the decimal delimiter .:

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;

But it's in the nature of floats to fool you. 1 may just as well be represented by 0.00000000989 or something. I'm not sure how well the above actually performs in real life applications.

Solution 5

Basing on @blackpla9ue comment and considering numbers exponential format:

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
Share:
41,632
JussiR
Author by

JussiR

Updated on January 19, 2022

Comments

  • JussiR
    JussiR over 2 years

    What I would like to have is the almost opposite of Number.prototype.toPrecision(), meaning that when i have number, how many decimals does it have? E.g.

    (12.3456).getDecimals() // 4
    
  • JussiR
    JussiR about 12 years
    Ok, good to know. Anyway, i'm only dealing with how decimal numbers are shown, so changing them to string an splitting with '.' seems to be thee answer.
  • jarib
    jarib almost 9 years
    If you pass NaN to this, it'll go into an infinite loop.
  • Justin
    Justin almost 9 years
    This is a good answer, but I recommend you check for edge cases, such as NaN or the Infinities, to avoid infinite looping. Also, it might come out better if you returned Math.round(Math.log(e) / Math.LN10) instead.
  • Eric Lagergren
    Eric Lagergren over 8 years
    Typically the number of digits in a given base is ceil(log-N(num))
  • STRML
    STRML over 8 years
    Just for kicks, put this in a jsperf compared to the string answer above. It's about 8x faster: jsperf.com/getting-numerical-precision/2
  • Mourner
    Mourner over 8 years
    Thanks for feedback everyone — added a faster, more complete solution.
  • Seraph
    Seraph about 7 years
    This is a nice algorithm, but unfortunately javascript's questionable Number type is not so nice after all. If you take for example: Number.MIN_VALUE which is indeed a finite and valid number with a precision of 324 and put it into your algorithm, you can wait until next year to get a result. The string representation would be infinitely faster for high precision numbers. Unfortunately, javascript will use the scientific notation for precisions > 20. Which invalidates the string solution mentioned here. So start with this: stackoverflow.com/a/1685917/1173210 . Won't be fast!
  • Piotr Aleksander Chmielowski
    Piotr Aleksander Chmielowski about 7 years
    (1.0 + "").split(".")[1].length; gives error because split returns one-character so we cannot access it's second ([1]) element.
  • Christian Grün
    Christian Grün about 7 years
    Something like this should work: function getPrecision(number) { var n = number.toString().split("."); return n.length > 1 ? n[1].length : 0; }
  • Christian Grün
    Christian Grün about 7 years
    Please note that the existing version still causes an endless loop if the input is invalid (e.g. an empty string).
  • Dan Dascalescu
    Dan Dascalescu almost 7 years
    This "accepted" answer is incorrect for the general case, as Piotr mentioned above. Also, this question is a duplicate.
  • Heath Dutton
    Heath Dutton over 5 years
    (12.3456 + '.').split('.')[1].length; works for all cases in getting the decimal place count.
  • Mourner
    Mourner about 5 years
    It does, since 123.000 is 12, and JS does not distinguish between the two.
  • mtx
    mtx almost 5 years
    @Mourner Edited version of your solution is still not handling edge cases, causes infinite loop for null and empty string.
  • mtx
    mtx almost 5 years
    it will fail when you put number without decimals or when you put string with dot (for example wat.wat), improved: function precision(num) { if (isNaN(+num)) return 0; const decimals = (num + '').split('.')[1]; if (decimals) return decimals.length; return 0; }
  • Edouard Menayde
    Edouard Menayde almost 5 years
    Still buggy, causes infinite loops... This can't be the accepted answer if not fixed...
  • ozm
    ozm over 4 years
    Maybe its better to add number check. if (typeof a !== "number" || !isFinite(a)) return 0;
  • hackape
    hackape over 3 years
    Float point error kicks in for case n = 0.44399999999999995, precision(n) == 18 while the face value precision should be 17.
  • Oleg Zarevennyi
    Oleg Zarevennyi about 3 years
    Probably edge case: 0.1**12==28, but 0.1**13==30! and 0.1**14==31
  • Benji
    Benji about 2 years
    If you add if (typeof a !== "number") a = parseFloat(a); if (isNaN(a)) return 0; as the first two lines in the function it will prevent the function call from getting stuck in a while loop if a string is passed.