164

I'm new to JavaScript and just discovered toFixed() and toPrecision() to round numbers. However, I can't figure out what the difference between the two is.

What is the difference between number.toFixed() and number.toPrecision()?

informatik01
  • 16,038
  • 10
  • 74
  • 104
Jessica
  • 1,651
  • 2
  • 10
  • 4

9 Answers9

152

toFixed(n) provides n length after the decimal point; toPrecision(x) provides x total length.

Ref at w3schools: toFixed and toPrecision

EDIT:
I learned a while back that w3schools isn't exactly the best source, but I forgot about this answer until I saw kzh's, uh, "enthusiastic" comment. Here are additional refs from Mozilla Doc Center for toFixed() and for toPrecision(). Fortunately for all of us, MDC and w3schools agree with each other in this case.

For completeness, I should mention that toFixed() is equivalent to toFixed(0) and toPrecision() just returns the original number with no formatting.

And of course, the real source of truth is the JS specification, which in this case is https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-number.prototype.toprecision

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
Pops
  • 30,199
  • 37
  • 136
  • 151
  • 12
    Bah, I posted this in July 2010, and I didn't learn about w3fools until this year. While fools is correct about some things, not _everything_ on schools is wrong. Thanks for pointing out that I need to update this post, though; will do it in a bit. – Pops Apr 18 '11 at 22:55
  • 33
    `toPrecision(x)` doesn't "provide `x` total length", it formats to a number of given significant digits. For example, `0.0000022.toPrecision(1)` would return `0.000002`. – Andy E May 06 '13 at 21:53
  • 9
    I just visited w3fools and was not convinced whatsoever. I don't even see any argument. All I see is an advertisement for two other sites. – NiCk Newman Mar 08 '16 at 04:12
73

I believe that the former gives you a fixed number of decimal places, whereas the latter gives you a fixed number of significant digits.

Math.PI.toFixed(2); // "3.14"
Math.PI.toPrecision(2); // "3.1"

Furthermore, toPrecision will yield scientific notation if there are more integer digits in the number than the specified precision.

(Math.PI * 10).toPrecision(2); // "31"
(Math.PI * 100).toPrecision(2); // "3.1e+2"

EDIT: Oh, and if you are new to JavaScript, I can highly recommend the book "JavaScript: The Good Parts" by Douglas Crockford.

Tom
  • 4,742
  • 25
  • 32
  • This answer doesn't explain this behavior: `(0.004).toPrecision(3) //'0.000400'`. I doubt that 'gives you a fixed number of significant digits' is an appropriate explanation – d.k Oct 23 '20 at 19:10
  • 1
    @DmitryKoroliov I think it does explain this. In your example, the digit '4' is the first significant digit, so when you request 3 significant digits, it must add two more, which in this case are both zeros – Tom Dec 09 '20 at 12:03
34

Examples speak clearly:

var A = 123.456789;

A.toFixed()      // 123
A.toFixed(0)     // 123
A.toFixed(1)     // 123.5      round up last
A.toFixed(2)     // 123.46     round up last
A.toFixed(3)     // 123.457    round up last
A.toFixed(4)     // 123.4568   round up last
A.toFixed(5)     // 123.45679  round up last
A.toFixed(6)     // 123.456789
A.toFixed(7)     // 123.4567890
A.toFixed(8)     // 123.45678900
A.toFixed(9)     // 123.456789000
A.toFixed(10)    // 123.4567890000
A.toFixed(11)    // 123.45678900000

A.toPrecision()      // 123.456789 
A.toPrecision(0)     // --- ERROR --- 
A.toPrecision(1)     // 1e+2
A.toPrecision(2)     // 1.2e+2
A.toPrecision(3)     // 123
A.toPrecision(4)     // 123.5      round up last
A.toPrecision(5)     // 123.46     round up last
A.toPrecision(6)     // 123.457    round up last
A.toPrecision(7)     // 123.4568   round up last
A.toPrecision(8)     // 123.45679  round up last
A.toPrecision(9)     // 123.456789
A.toPrecision(10)    // 123.4567890
A.toPrecision(11)    // 123.45678900

// ----------------------
// edge-case rounding
// ----------------------
var B = 999.99;
B.toFixed(0)      // 1000
B.toFixed(1)      // 1000.0
B.toFixed(2)      // 999.99
B.toFixed(3)      // 999.990

B.toPrecision(0)  // --- ERROR ----
B.toPrecision(1)  // 1e+3
B.toPrecision(2)  // 1.0e+3
B.toPrecision(3)  // 1.00e+3
B.toPrecision(4)  // 1000
B.toPrecision(5)  // 999.99
B.toPrecision(6)  // 999.990

var C = 0.99;
C.toFixed(0)      // 1
C.toFixed(1)      // 1.0
C.toFixed(2)      // 0.99
C.toFixed(3)      // 0.990

C.toPrecision(0)  // --- ERROR ----
C.toPrecision(1)  // 1
C.toPrecision(2)  // 0.99
C.toPrecision(3)  // 0.990
bob
  • 7,539
  • 2
  • 46
  • 42
11

I think this is best answered with an example.

Let's say you have the following data:

var products = [
  {
    "title": "Really Nice Pen",
    "price": 150
  },
  {
    "title": "Golf Shirt",
    "price": 49.99
  },
  {
    "title": "My Car",
    "price": 1234.56
  }
]

You want to display each of these products with the title and formatted price. Let's try using toPrecision first:

document.write("The price of " + products[0].title + " is $" + products[0].price.toPrecision(5));

The price of Really Nice Pen is $150.00

Looks good, so you might think this will work for the other products as well:

document.write("The price of " + products[1].title + " is $" + products[2].price.toPrecision(5));
document.write("The price of " + products[2].title + " is $" + products[2].price.toPrecision(5));

The price of Golf Shirt is $49.990
The price of My Car is $1234.6

Not so good. We can fix this by changing the number of significant digits for each product, but if we're iterating over the array of products that could be tricky. Let's use toFixed instead:

document.write("The price of " + products[0].title + " is $" + products[0].price.toFixed(2));
document.write("The price of " + products[1].title + " is $" + products[2].price.toFixed(2));
document.write("The price of " + products[2].title + " is $" + products[2].price.toFixed(2));

The price of Really Nice Pen is $150.00
The price of Golf Shirt is $49.99
The price of My Car is $1234.56

This produces what you expected. There is no guess work involved, and there is no rounding.

Big McLargeHuge
  • 14,841
  • 10
  • 80
  • 108
6

Just:

49.99.toFixed(5)
// → "49.99000"

49.99.toPrecision(5)
// → "49.990"
5

Under certain circumstances, toPrecision() will return exponential notation, whereas toFixed() will not.

Robusto
  • 31,447
  • 8
  • 56
  • 77
  • Actually, `toExponential()` is a [separate function](http://www.w3schools.com/jsref/jsref_toexponential.asp). – Pops Jul 26 '10 at 18:43
  • 5
    @Lord Torgamus: According to my copy of *Javascript: The Definitive Guide*, toPrecision(precision) will use fixed-point notation if the *precision* arg is large enough to include all the digits of the integer part of the number. Otherwise, exponential notation is used. – Robusto Jul 26 '10 at 18:46
  • In at least some cases, this is not correct: in my Firefox, with `a = 999999999999999934464;`, `a.toFixed(0)` returns `"1e+21"`. Perhaps a more accurate answer would be that toFixed() does not return exponential notation unless toString() does. – the paul Dec 30 '18 at 00:22
2

toFixed(fractionDigits?) has been explained more or less accurately in other answers:

  • it returns a string representation of the number with fractionDigits [amount] digits after the decimal point:

An example:

(-3).toFixed(1)     // '-3.0'
(-3).toFixed(0)     // '-3'
(-3).toFixed()      // '-3'
(-0.03).toFixed(1)  // '-0.0'

toPrecision(precision?) has not been described correctly in the previous answers, so one should pay attention. Also I'd add a disclaimer, that I haven't been able to digest the spec on toPrecision, so the next points are based on the try and error approach of testing the implementation in Node.js. And these steps don't cover all corner cases like what if the number is NaN, or the precision arg is not integer, or is <1 or >100 etc. This is in order not to make the explanation cluttered as the spec seems to be.

*Numbering of cases is preserved thru the list, despite cases may seem similar to other, they are required to demonstrate a particular behavior

  1. it first represents the number in exponential notation with precision being the number of digits in the significand, like

Case 1: 0.000004 → precision = 3 → 400 * 10^-8
Case 2: 0.0000004 → precision = 3 → 400 * 10^-9
Case 3: 123 → precision = 1 → 1.23 * 10^2
Case 4: 153 → precision = 1 → 1.53 * 10^2
Case 5: 1234.56 → precision = 3 → 123.456 * 10^1
Case 6: 1234.56 → precision = 5 → 12345.6 * 10^-1

  1. then it rounds the significand part

Case 1: 400 * 10^-8400 * 10^-8 (no fraction was present, no change)
Case 2: 400 * 10^-9400 * 10^-9 (same reasoning as in case 1)
Case 3: 1.23 * 10^21 * 10^2 (1.23 was rounded to 1)
Case 4: 1.53 * 10^22 * 10^2 (1.53 rounded to 2)
Case 5: 123.456 * 10^1123 * 10^1 (rounded too)
Case 6: 12345.6 * 10^-112346 * 10^-1 (rounded)

  1. then it produces a string representation of the number following the rules:

3a) all digits from the significand in step 2 will be preserved

3b) Exponential notation is used if precision < the number of digits before the point (in 'normal', i.e. decimal representation)

Case 3: 1 * 10^2'1e+2' (number is now 100, 3 digits, precision is 1, exponent is used)
Case 4:2 * 10^2'2e+2' (number is now 200, 3 digits, precision is 1, exponent is used)
Case 5:123 * 10^1'1.23e+3' (number is now 1230, 4 digits, precision is 3, exponent is used; note that the significand has preserved all digits from step 2: 123 became 1.23)

3c) Exponential notation is used if the number has the 0 integer part and the number of zeros right after the decimal point and before the first significant digit (in 'normal' notation) is >5

Case 2: 400 * 10^-9'4.00e-7' (number is 0.0000004, it has the 0 integer part and there are >5 zeros after the decimal point, note that the two zeros from 400 * 10^-9 were preserved)

3d) Decimal notation is used, if the number has the 0 integer part and the number of zeros right after the decimal point <= 5 but the digits from the significand from step 2 will be preserved

Case 1: 400 * 10^-8'0.00000400' (the two zeros from the significand part have been preserved)

3e) Decimal notation is used, if precision >= the number of digits before the point in decimal representation

Case 6: 12346 * 10^-11234.6 (the decimal form of the number in step 2 is 1234.6, precision is 5, number of digits before the decimal point is 4, the string uses decimal notation, all digits from the significand in step 2 were preserved)

console.log((0.000004).toPrecision(3));
console.log((0.0000004).toPrecision(3));
console.log((123).toPrecision(1));
console.log((153).toPrecision(1));
console.log((1234.56).toPrecision(3));
console.log((1234.56).toPrecision(5));
d.k
  • 4,234
  • 2
  • 26
  • 38
  • Well, that might explain weirdness like `999.9` `toPrecisison(3)` coming out as `1.00e+3` instead of `999` or `1`.... How might one get around such things? – Douglas Gaskell Dec 14 '21 at 05:13
1

For example , we consider the variable a as, var a = 123.45 a.toPrecision(6) The output is 123.450 a.toFixed(6) The output is like 123.450000 // 6 digits after decimal point

Monica Acha
  • 1,076
  • 9
  • 16
0

Both toPrecision() and toFixed() are functions designed to format a number before printing it out. So they both return String values.

There is one exception. If you use these functions on a negative Number literal, due to operator precedence, a Number is returned. What this means is that toFixed() or toPrecision() will return a string first, and then the - minus operator will convert the string back to a Number as a negative value. Please see below for an example.

toPrecision() returns a String representing the Number object in fixed-point or exponential notation rounded to significant digits. So if you specify that you want a precision of 1, it returns the first significant number along with either scientific notation to indicate the powers of 10 or the previous 0's before its decimal point if the significant number is < 0.

const num1 = 123.4567;

// if no arguments are passed, it is similar to converting the Number to String
num1.toPrecision();   // returns "123.4567

// scientific notation is used when you pass precision count less than total
// number of digits left of the period
num1.toPrecision(2);  // returns "1.2e+2"

// last digit is rounded if precision is less than total significant digits
num1.toPrecision(4);  // returns "123.5"
num1.toPrecision(5);  // returns "123.46"

const largeNum = 456.789;
largeNum.toPrecision(2);  // returns "4.6e+2"

// trailing zeroes are added if precision is > total digits of the number or float
num1.toPrecision(9);  // returns "123.456700"

const num2 = 123;
num2.toPrecision(4);  // returns "123.0"

const num3 = 0.00123;
num3.toPrecision(4);  // returns "0.001230"
num3.toPrecision(5);  // returns "0.0012300"

// if the number is < 1, precision is by the significant digits
num3.toPrecision(1);  // returns "0.001"

toFixed() returns a String representing the Number object in fixed-point notation, rounded up. This function only cares about the decimal point numbers

const num1 = 123.4567;

// if no argument is passed, the fractions are removed
num1.toFixed();  // returns "123"

// specifying an argument means you the amount of numbers after the decimal point
num1.toFixed(1);  // returns "123.5"
num1.toFixed(3);  // returns "123.457"
num1.toFixed(5);  // returns "123.45670"
num1.toFixed(7);  // returns "123.4567000"

// trying to operator on number literals
2.34.toFixed(1);  // returns "2.3"
2.toFixed(1);     // returns SyntaxError
(2).toFixed(1);   // returns "2.0"
(2.34e+5).toFixed(1);  // returns "234000.0"

I mentioned above an exception where using these functions on negative Number literals will return a Number and not a String due to operator precedence. Here are some examples:

// Note: these are returning as Number
// toPrecision()
-123.45.toPrecision();  // returns -123.45
-123.45.toPrecision(2);  // returns -120
-123.45.toPrecision(4);  // returns -123.5
-2.34e+2.toPrecision(1);  // returns -200
-0.0456.toPrecision(1);  // returns -0.05
-0.0456.toPrecision(6);  // returns -0.0456

// toFixed()
-123.45.toFixed();  // returns -123.45
-123.45.toFixed(1);  // returns -123.5
-123.45.toFixed(4);  // returns -123.45
-0.0456.toFixed(1);  // returns -0
-0.0456.toFixed(6);  // -0.0456

Fun fact: there are signed zeroes as seen from -0.0456.toFixed(1)

See: Are +0 and -0 the same?

philip yoo
  • 2,462
  • 5
  • 22
  • 37