284

Am I missing something here?

var someNumber = 123.456; someNumber = someNumber.toFixed(2); alert(typeof(someNumber)); //alerts string 

Why does .toFixed() return a string?

I want to round the number to 2 decimal digits.

6
  • 12
    Because it is designed to return a string? Commented Feb 17, 2010 at 19:04
  • 7
    To me it just seems odd. .toFixed() only operates on numbers... right? Commented Feb 17, 2010 at 19:07
  • 22
    I understand Math.round() works as expected. I was just enquiring why a function that operates on numbers returns a string... Commented Feb 17, 2010 at 19:09
  • 5
    People living in 2017 should use libraries like lodash.com/docs/4.17.4#ceil Commented Jun 12, 2017 at 19:07
  • 1
    So does _. count? not upgraded to his bro yet. Commented Jun 23, 2017 at 16:55

16 Answers 16

277

Number.prototype.toFixed is a function designed to format a number before printing it out. It's from the family of toString, toExponential and toPrecision.

To round a number, you would do this:

someNumber = 42.008; someNumber = Math.round( someNumber * 1e2 ) / 1e2; someNumber === 42.01; // if you need 3 digits, replace 1e2 with 1e3 etc. // or just copypaste this function to your code: function toFixedNumber(num, digits, base){ const pow = Math.pow(base ?? 10, digits); return Math.round(num*pow) / pow; } 

Why isn't this function included in the JavaScript's standard library? Because floating point numbers are hard! Many decimal numbers cannot be directly represented by base-two floats – that's why 0.09 + 0.01 !== 0.1 but 0.09999999999999999. If developers were given a tool which is supposed to round floats to decimal places, they'd (wrongly) assume that it really returns a decimal number, when it in fact returns the closest representable double-precision base-two float.

Sign up to request clarification or add additional context in comments.

9 Comments

I think this is the best answer. It avoids type conversion. Awesome-sauce!
Great answer! However... I've been doing JavaScript like 20 years or so, but I can't figure out why you're using that +(...) construction around the return value? Thanks @sam for rubbing it in :) As I'm never too old to learn, please elaborate :-)
@HammerNL Despite Sam's conviction, it acutally doesn't do anything :) It's just a practise – it makes IDEs recognize this function as type Number. The thing is that +(anyValue) always returns a number – eg. +("45") returns 45, +(new Number(42)) returns 42. It's kinda like strong-typing the function. If you make a habit of it, you can avoid a lot of bugs :)
Why is this not baked into core javascript :s
The resuit of someNumber = Math.round( 42.008 * 1e2 ) / 1e2; is not 42.01, it is ~42.0099999999999980. Reason: The number 42.01 does not exists and is rounded to the nearest existing number. btw, proof numbers by toPrecision(18) to print it with all relevant digits.
|
172

I've solved this problem by changing this:

someNumber = someNumber.toFixed(2) 

...to this:

someNumber = +someNumber.toFixed(2); 

However this will convert the number to a string and parse it again, which will have a significant impact on performance. If you care about performance or type safety, check the the other answers as well.

9 Comments

No, no, no, no, no! Don't do that! Number to string conversion just to round it is a very bad practise! Instead do someNumber = Math.round(someNumber * 1e2) / 1e2! See my answer for a more generalized way.
@jczaplew Because if you do it this way, the 32bit binary number is converted into a string, using 16bits for every god-damn decimal digit! (By the way storing numbers in UTF-16 isn't the most convenient thing you'd go for.) And than the string is converted back to a 32bit floating-point number. Digit by digit. (If I ignore all the tests that must be done before to chose the right parsing algorithm.) And all that in vain considering you can do it using 3 fast operations on the float.
@m93a so it's for performance reasons? does this actually have a noticeable impact in performance?
@jczaplew, Because Strings are (1) practically slow and (2) theoretically incorrect.
Math.round(someNumber * 1e2) / 1e2 is very easy to remember. JavaScript is such fun 😁🤣😜
|
149

It returns a string because 0.1, and powers thereof (which are used to display decimal fractions), are not representable (at least not with full accuracy) in binary floating-point systems.

For example, 0.1 is really 0.1000000000000000055511151231257827021181583404541015625, and 0.01 is really 0.01000000000000000020816681711721685132943093776702880859375. (Thanks to BigDecimal for proving my point. :-P)

Therefore (absent a decimal floating point or rational number type), outputting it as a string is the only way to get it trimmed to exactly the precision required for display.

11 Comments

at least javascript could save me some finger-work and convert it back to a number... sheesh...
@Derek: Yeah, but once you convert it back into a number, you run into the same inaccuracy issues again. :-P JS doesn't have decimal floating point or rational numbers.
Actually this caused me to do some pretty heavy research into this subject! thanks for all your help!
Your answer is slightly misleading: toFixed is a formatting function, which has a sole purpose of converting a number to a string, formatting it using the specified number of decimals. The reason it returns a string is because it's supposed to return a string, and if it was named toStringFixed instead, OP wouldn't be surprised at the results. The only issue here is that OP expected it to work like Math.round, without consulting JS reference.
@jbyrd It would be, except that 5.95 doesn't exist. What that gets parsed into, instead, is 5.95000000000000017763568394002504646778106689453125. If you're willing to deal with that kind of difference, cool. Just know that an API cannot actually send 5.95 exactly, at least not as a JSON number.
|
47

Why not use parseFloat?

var someNumber = 123.456; someNumber = parseFloat(someNumber.toFixed(2)); alert(typeof(someNumber)); //alerts number 

1 Comment

Or simply + sign instead of parseFloat() to convert to number.
27

I solved it with converting it back to number using JavaScript's Number() function

var x = 2.2873424; x = Number(x.toFixed(2)); 

Comments

16

Of course it returns a string. If you wanted to round the numeric variable you'd use Math.round() instead. The point of toFixed is to format the number with a fixed number of decimal places for display to the user.

Comments

8

You can simply use a '+' to convert the result to a number.

var x = 22.032423; x = +x.toFixed(2); // x = 22.03 

Comments

6

May be too late to answer but you can multiple the output with 1 to convert to number again, here is an example.

const x1 = 1211.1212121; const x2 = x1.toFixed(2)*1; console.log(typeof(x2));

Comments

3

What would you expect it to return when it's supposed to format a number ? If you have a number you can't pretty much do anything with it because e.g.2 == 2.0 == 2.00 etc. so it has to be a string.

Comments

3

Because its primary use is displaying numbers? If you want to round numbers, use Math.round() with apropriate factors.

4 Comments

but it's displaying NUMBERS so shouldn't it return a "number"?
@Derek: Only in the way that '42' is a number...which it's not. Just because a string happens to contain digits only does not make it a number. This isn't PHP. :-P
lol. It's not a string that contains a number... It's a number that is passed to a method. The method takes a number and returns a string.
@DerekAdair right but a browser can't display a Number, it displays strings, thus the conversion.
3

Here's a slightly more functional version of the answer m93a provided.

const toFixedNumber = (toFixTo = 2, base = 10) => num => { const pow = Math.pow(base, toFixTo) return +(Math.round(num * pow) / pow) } const oneNumber = 10.12323223 const result1 = toFixedNumber(2)(oneNumber) // 10.12 const result2 = toFixedNumber(3)(oneNumber) // 10.123 // or using pipeline-operator const result3 = oneNumber |> toFixedNumber(2) // 10.12 

1 Comment

it's handy function, for undefined type it does not work, I have added code for this case; if (num !== undefined) { return +(Math.round(num * pow) / pow) }else { return 0; }
3

To supply an example of why it has to be a string:

If you format 1.toFixed(2) you would get '1.00'.

This is not the same as 1, as 1 does not have 2 decimals.


I know JavaScript isn't exactly a performance language, but chances are you'd get better performance for a rounding if you use something like: roundedValue = Math.round(value * 100) * 0.01

Comments

3

For others like me that happen upon this very old question, a modern solution:

const roundValue = (num, decimals = 2) => { let scaling = 10 ** decimals; return Math.round((num + Number.EPSILON) * scaling) / scaling; } 

ref: https://stackoverflow.com/a/11832950

Comments

3

You should use it like below.

var someNumber: number = 0.000000; someNumber = Number(someNumber.toFixed(2)) 

1 Comment

It won’t give you decimal values anymore
3

Why not * the result by 1 i.e

someNumber.toFixed(2) * 1

1 Comment

It won’t give you decimal values anymore after * 1.
0

Be careful using toFixed() and Math.round(), they can produce unexpected results due to the floating point number system:

function toFixedNumber(num, digits, base){ var pow = Math.pow(base||10, digits); return Math.round(num*pow) / pow; } console.log(toFixedNumber(130.795, 2, 10)); // 130.79 (incorrect) console.log(toFixedNumber(100.795, 2, 10)); // 100.8 console.log(+130.795.toFixed(2)); // 130.79 (incorrect) console.log(+100.795.toFixed(2)); // 100.8 

I recommend using Lodash's _.round() function: https://lodash.com/docs/4.17.15#round

_.round(130.795, 2); // 130.8 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.