298

Suppose I have a value of 15.7784514, I want to display it 15.77 with no rounding.

var num = parseFloat(15.7784514);
document.write(num.toFixed(1)+"<br />");
document.write(num.toFixed(2)+"<br />");
document.write(num.toFixed(3)+"<br />");
document.write(num.toFixed(10));

Results in -

15.8
15.78
15.778
15.7784514000 

How do I display 15.77?

Salman A
  • 262,204
  • 82
  • 430
  • 521
tempid
  • 7,838
  • 28
  • 71
  • 101
  • 81
    It's useful when displaying currency. – Richard Ye Dec 16 '12 at 05:00
  • @ mik01aj - When displaying currency, it is more common to truncate calculated values, rather than rounding them. For example, most tax forms in the US truncate rather than round calculated fractional cents. In that case, the truncated value is the correct value. – Steven Byks Feb 10 '17 at 18:06
  • Simpler solution: [Truncate to decimals function](https://stackoverflow.com/a/44184500/2086460) – David May 25 '17 at 15:44
  • 1
    I have no idea why you would want to run `parseFloat` on a float. It's already a float, so no need to parse it. So - do you initially have a `string` or a `number`? – user202729 Jun 25 '18 at 14:42
  • 10
    @CamiloMartin there is a huge difference between a debt of 1.49 billion dollars and 1.0 billion dollars. – Broda Noel Feb 01 '19 at 20:07
  • 14
    There is also a huge difference between 1.49 billion and 1.50 billion dollars. That's $100 million. – Liga Sep 24 '19 at 08:05
  • 4
    If you round $1.49B of currency, you could end up telling someone they have $1.5B. They will be disappointed at checkout, and will have to remove $1.5B 'Eclipse' Luxury Mega Yacht from cart. – Rob Oct 28 '21 at 11:34
  • can i just do this `15.7784514.toFixed(3).slice(0, -1)` call it a day? – Layhout Aug 05 '23 at 03:48

43 Answers43

281

Convert the number into a string, match the number up to the second decimal place:

function calc(theform) {
    var num = theform.original.value, rounded = theform.rounded
    var with2Decimals = num.toString().match(/^-?\d+(?:\.\d{0,2})?/)[0]
    rounded.value = with2Decimals
}
<form onsubmit="return calc(this)">
Original number: <input name="original" type="text" onkeyup="calc(form)" onchange="calc(form)" />
<br />"Rounded" number: <input name="rounded" type="text" placeholder="readonly" readonly>
</form>

The toFixed method fails in some cases unlike toString, so be very careful with it.

LWC
  • 1,084
  • 1
  • 10
  • 28
Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • 26
    +1 That should solve the rounding issue. I'd still output the result of the above using `toFixed`, though, so: `(Math.floor(value * 100) / 100).toFixed(2)`. As you probably know, weird precision things can happen with floating point values (and on the other side of the spectrum, if the number happens to be `15`, sounds like the OP wants `15.00`). – T.J. Crowder Nov 15 '10 at 17:38
  • 1
    hehe, or if you combine both: `Number((15.7784514000*100).toString().match(/^\d+/)/100);` – skobaljic Oct 21 '13 at 12:08
  • 33
    Math.floor(value * 100) / 100 won't work if value = 4.27 seriously, try it. – Dark Hippo Jan 17 '14 at 16:56
  • 4
    @DarkHippo Thats because 4.27 is actually 4.26999999999, Math.round is generally a better solution, albeit not the answer to the original question. Realistically given the output is a string this should be done using string manipulation instead of a numeric solution with all the floating point foibles. – BJury Apr 02 '14 at 10:04
  • 1
    How is this the accepted answer? There are serious problems with the `Math.floor(15.7784514000 * 100) / 100` approach. If you have a multiplication inside a Math.floor() function it WILL FAIL for some numbers! Floating point arithmetic is NOT ACCURATE and you need to use different methods, such as the RegEx. Stop upvoting this answer you're spreading bad code around. As mentioned above try `4.27` in that function and it will fail. – Nico Westerdale Nov 04 '16 at 15:36
  • 3
    ...that doesn't sound right. Converting between types under any circumstances seems roundabout and unsafe. Unless a really advanced programmer would argue that "all types are just streams" or something. – JackHasaKeyboard Aug 18 '17 at 06:19
  • @BJury "thats because 4.27 is actually 4.26999999999" , I don't think that statement is correct - the problem only occurs if you add/subtract/multiply. I think on it's own, 4.27 is 4.27 – Drenai Dec 05 '17 at 15:25
  • 1
    Unfortunately, try `0.00000001990202020291` and you'll get `1.99`. The issue is that if you just return that long decimal JS turns it into `1.99020202029e-8` first and I don't know how to get around that. Does anyone have any suggestions @IvanCastellanos – bryan Jan 06 '18 at 18:19
  • `theform.original.value` is **already** a `string`. Why do you need to `toString()` it? – user202729 Jun 26 '18 at 10:10
  • Is there a way to always show 2 decimals with this solution? Like toFixed kind of thing. – Julius Sep 05 '18 at 09:11
  • it fails if we don't add any value before decimal i.e .9 – Anubhav Gupta Mar 09 '20 at 07:39
  • 2
    @AnubhavGupta To make it work without values before the decimal just change the + in the regex into as * so you get: `match(/^-?\d*(?:\.\d{0,2})?/) ` – Bart Enkelaar May 07 '20 at 18:51
  • How to keep precision value in a variable? like match(/^-?\d+(?:\.\d{0, "here variable" })?/)[0] – ksh Jun 01 '21 at 10:21
  • I want to truncate this number: `99999999999999.9999` to 4 decimal places but it results in: `100000000000000.0000`, please help me out? – FaizanHussainRabbani Aug 30 '21 at 17:21
101

Update 5 Nov 2016

New answer, always accurate

function toFixed(num, fixed) {
    var re = new RegExp('^-?\\d+(?:\.\\d{0,' + (fixed || -1) + '})?');
    return num.toString().match(re)[0];
}

As floating point math in javascript will always have edge cases, the previous solution will be accurate most of the time which is not good enough. There are some solutions to this like num.toPrecision, BigDecimal.js, and accounting.js. Yet, I believe that merely parsing the string will be the simplest and always accurate.

Basing the update on the well written regex from the accepted answer by @Gumbo, this new toFixed function will always work as expected.


Old answer, not always accurate.

Roll your own toFixed function:

function toFixed(num, fixed) {
    fixed = fixed || 0;
    fixed = Math.pow(10, fixed);
    return Math.floor(num * fixed) / fixed;
}
guya
  • 5,067
  • 1
  • 35
  • 28
  • 7
    toFixed(4.56, 2) = 4.55 – cryss Oct 31 '16 at 09:17
  • 3
    So many of these answers have a multiplication inside a Math.floor() function. This will fail for some numbers! Floating point arithmetic is not accurate and you need to use different methods. – Nico Westerdale Nov 04 '16 at 15:33
  • 1
    function toFixedCustom(num, fixed) { var re = new RegExp('^-?\\d+(?:\.\\d{0,' + (fixed || -1) + '})?'); if(num.toString().match(re) ){ return num.toString().match(re)[0]; } } – Ryan Augustine May 08 '18 at 10:26
  • 8
    The updated answer will fail for a number big or small enough that javascript would represent in scientific notation. `toFixed(0.0000000052, 2)` yields '5.2'. This can be fixed by using `return num.toFixed(fixed+1).match(re)[0];` Notice I'm using toFixed with one decimal place above the target to avoid rounding, then running your regex match – Netherdan Sep 27 '19 at 12:49
  • @guya, I'm pretty sure -0.001 will return -0.00. I think in most cases you will want either 0 or 0.00 without the negative symbol. – Jonny B Sep 29 '20 at 22:51
  • Please DO NOT use the to fixed version, eg: if a = 10.20, a * 100 returns 1019.9999999 – George Jan 18 '23 at 14:07
  • 1
    @George, use the **New answer, always accurate** `toFixed(10.20, 2)` returns `10.2` – guya Jan 21 '23 at 14:07
73

Another single-line solution :

number = Math.trunc(number*100)/100

I used 100 because you want to truncate to the second digit, but a more flexible solution would be :

number = Math.trunc(number*Math.pow(10, digits))/Math.pow(10, digits)

where digits is the amount of decimal digits to keep.

See Math.trunc specs for details and browser compatibility.

T. Junghans
  • 11,385
  • 7
  • 52
  • 75
remidej
  • 1,428
  • 1
  • 14
  • 21
  • 4
    This is the best answer if you do not have to support IE11. – T. Junghans Jun 26 '20 at 14:24
  • 16
    @T.Junghans Sorry but this doesn't work: (4.27, 2) => 4.26 and that happens regardless of IE11 or any other browser. – ingdc Feb 28 '21 at 17:20
  • it's the year 2023 and `Math.trunc(number*100)/100` totally works - was using it on lat lng values (ins SAFARI (the new IE) no less) and it delivered – flaky Aug 10 '23 at 15:10
49

I opted to write this instead to manually remove the remainder with strings so I don't have to deal with the math issues that come with numbers:

num = num.toString(); //If it's not already a String
num = num.slice(0, (num.indexOf("."))+3); //With 3 exposing the hundredths place
Number(num); //If you need it back as a Number

This will give you "15.77" with num = 15.7784514;

ベンノスケ
  • 619
  • 6
  • 7
30

Update (Jan 2021)

Depending on its range, a number in javascript may be shown in scientific notation. For example, if you type 0.0000001 in the console, you may see it as 1e-7, whereas 0.000001 appears unchanged (0.000001). If your application works on a range of numbers for which scientific notation is not involved, you can just ignore this update and use the original answer below.

This update is about adding a function that checks if the number is in scientific format and, if so, converts it into decimal format. Here I'm proposing this one, but you can use any other function that achieves the same goal, according to your application's needs:

function toFixed(x) {
  if (Math.abs(x) < 1.0) {
    let e = parseInt(x.toString().split('e-')[1]);
    if (e) {
        x *= Math.pow(10,e-1);
        x = '0.' + (new Array(e)).join('0') + x.toString().substring(2);
    }
  } else {
    let e = parseInt(x.toString().split('+')[1]);
    if (e > 20) {
        e -= 20;
        x /= Math.pow(10,e);
        x += (new Array(e+1)).join('0');
    }
  }
  return x;
}

Now just apply that function to the parameter (that's the only change with respect to the original answer):

function toFixedTrunc(x, n) {
      x = toFixed(x) 

      // From here on the code is the same than the original answer
      const v = (typeof x === 'string' ? x : x.toString()).split('.');
      if (n <= 0) return v[0];
      let f = v[1] || '';
      if (f.length > n) return `${v[0]}.${f.substr(0,n)}`;
      while (f.length < n) f += '0';
      return `${v[0]}.${f}`
    }

This updated version addresses also a case mentioned in a comment:

toFixedTrunc(0.000000199, 2) => "0.00" 

Again, choose what fits your application needs at best.

Original answer (October 2017)

General solution to truncate (no rounding) a number to the n-th decimal digit and convert it to a string with exactly n decimal digits, for any n≥0.
function toFixedTrunc(x, n) {
  const v = (typeof x === 'string' ? x : x.toString()).split('.');
  if (n <= 0) return v[0];
  let f = v[1] || '';
  if (f.length > n) return `${v[0]}.${f.substr(0,n)}`;
  while (f.length < n) f += '0';
  return `${v[0]}.${f}`
}

where x can be either a number (which gets converted into a string) or a string.

Here are some tests for n=2 (including the one requested by OP):

0           => 0.00
0.01        => 0.01
0.5839      => 0.58
0.999       => 0.99
1.01        => 1.01
2           => 2.00
2.551       => 2.55
2.99999     => 2.99
4.27        => 4.27
15.7784514  => 15.77
123.5999    => 123.59

And for some other values of n:

15.001097   => 15.0010 (n=4)
0.000003298 => 0.0000032 (n=7)
0.000003298257899 => 0.000003298257 (n=12)
ingdc
  • 760
  • 10
  • 16
  • 4
    `toFixedTrunc(0.000000199, 2) // 1.99 ` – Maharramoff May 19 '19 at 21:34
  • 1
    SC1000, I’m not sure how to interpret your answer to @Maharramoff. Are you saying that because there’s an explanation as to why your code sometimes fails, the code is correct? Or are you saying that 1.99 is the proper result of truncating 0.000000199 to 2 decimal places? – Philippe-André Lorin Jan 22 '21 at 16:02
  • @SC1000 You’re just explaining why your approach fails. The problem is your assumption that numbers would only have one possible string representation, and that this representation would be “0.000000199” for 0.000000199. If the language doesn’t guarantee that, relying on it is a mistake. – Philippe-André Lorin Jan 24 '21 at 19:06
  • 1
    @Maharramoff and others interested in the toFixedTrunc(0.000000199, 2) case, please refer to the updated answer (Jan 2021). Thanks. – ingdc Jan 30 '21 at 10:20
14

parseInt is faster then Math.floor

function floorFigure(figure, decimals){
    if (!decimals) decimals = 2;
    var d = Math.pow(10,decimals);
    return (parseInt(figure*d)/d).toFixed(decimals);
};

floorFigure(123.5999)    =>   "123.59"
floorFigure(123.5999, 3) =>   "123.599"
Martin Varmus
  • 157
  • 1
  • 2
13
num = 19.66752
f = num.toFixed(3).slice(0,-1)
alert(f)

This will return 19.66

The_Black_Smurf
  • 5,178
  • 14
  • 52
  • 78
Alex Peng
  • 147
  • 1
  • 3
9

Simple do this

number = parseInt(number * 100)/100;
a--m
  • 4,716
  • 1
  • 39
  • 59
Imran Pollob
  • 453
  • 6
  • 8
8

This is not a safe alternative, as many others commented examples with numbers that turn into exponential notation, that scenery is not covered by this function

// typescript
// function formatLimitDecimals(value: number, decimals: number): number {

function formatLimitDecimals(value, decimals) { 
  const stringValue = value.toString();
  if(stringValue.includes('e')) {
      // TODO: remove exponential notation
      throw 'invald number';
  } else {
    const [integerPart, decimalPart] = stringValue.split('.');
    if(decimalPart) {
      return +[integerPart, decimalPart.slice(0, decimals)].join('.')
    } else {
      return integerPart;
    }
  }
}

console.log(formatLimitDecimals(4.156, 2)); // 4.15
console.log(formatLimitDecimals(4.156, 8)); // 4.156
console.log(formatLimitDecimals(4.156, 0)); // 4
console.log(formatLimitDecimals(0, 4)); // 0

// not covered
console.log(formatLimitDecimals(0.000000199, 2)); // 0.00
7

Just truncate the digits:

function truncDigits(inputNumber, digits) {
  const fact = 10 ** digits;
  return Math.floor(inputNumber * fact) / fact;
}
Aral Roca
  • 5,442
  • 8
  • 47
  • 78
  • Thanks. Of course you can add this to prototype: `Number.prototype.truncDigits = function (digits) { const fact = 10 ** digits; return Math.floor(this.valueOf() * fact) / fact; }`. So you can use it as: `num.truncDigits(3)` – Elihai David Vanunu Sep 05 '21 at 11:40
6

These solutions do work, but to me seem unnecessarily complicated. I personally like to use the modulus operator to obtain the remainder of a division operation, and remove that. Assuming that num = 15.7784514:

num-=num%.01;

This is equivalent to saying num = num - (num % .01).

jtrick
  • 1,329
  • 18
  • 23
  • 1
    That's interesting Nijkokun, thanks for pointing it out. I've never run into problems using this technique, but clearly I should take a closer look for instances like this. As an alternative you could use ((num*=100)-(num%1))/100 which resolves this issue. The priority in my case is execution speed because of the volume of calculations I'm applying this to, and this is the fastest way of achieving this that I've found. – jtrick Feb 05 '15 at 03:36
  • 1
    The point was to avoid the object and function lookups and conversions required in the other solutions offered. Thanks for the feedback! – jtrick Feb 05 '15 at 03:46
  • 1
    also fails with negatives as -5 – Ruslan López Jun 08 '16 at 21:40
  • I'm also interested in a fast rounding, how would you make this code do 1 decimal? – thednp Dec 02 '16 at 02:04
  • HI thanks about very intellegant sulotion. But it doesn't work if number shorter then required round: `a = 1.2585; a -= a % .00001; a` now is `1.25849` – Elihai David Vanunu Sep 05 '21 at 11:32
6

Updated in 2023

There is one problem that no one has addressed: What to do with negative zeros ?

Should toFixed_norounding(-0.0000001, 2) be "-0.00" or "0.00" ? In my application it is preferred to make it "0.00"

I created this updated version for negative and positive numbers, with tests, uncomment if you need negative zeros:

function toFixed_norounding(n,p)
{
    var result = n.toFixed(p);
    result = Math.abs(result) <= Math.abs(n) ? result: (result - Math.sign(n) * Math.pow(0.1,p)).toFixed(p);

    // if you want negative zeros (-0.00), use this instead:
    // return result;

    // fixes negative zeros:
    if(result == 0) return (0).toFixed(p);
    else return result;
}

// tests:
[
    ["-1.99", -1.999999999999999,2],
    ["1.99", 1.999999999999999,2],
    ["-1.9", -1.999999999999999,1],
    ["1.9", 1.999999999999999,1],
    ["-1", -1.999999999999999,0],
    ["1", 1.999999999999999,0],
    ["4.56", 4.56, 2],
    ["-4.56", -4.56, 2],
    ["0.00", 0.00000000052, 2],
    //["-0.00", -0.00000000052, 2], // allow negative zeros
    ["0.00", -0.00000000052, 2], // don't
    ["0.00", 0.000000000, 2],
    ["0.00", -0.000000000, 2],
    ["4.27", 4.27, 2],
    ["-4.27", -4.27, 2],
    ["0.00", 0.000000199, 2],
    //["-0.00", -0.000000199, 2], // allow negative zeros
    ["0.00", -0.000000199, 2], // don't
    ["1234567.89", 1234567.89, 2],
    ["-1234567.89", -1234567.89, 2],
    ["4.999", 4.9999, 3],
    ["-4.999", -4.9999, 3],
].forEach( a => {
    if(!( a[0] === toFixed_norounding(a[1],a[2]) )) console.log("test failed:", a, "result: ", toFixed_norounding(a[1],a[2]));
});

Fast, pretty, obvious.

6

I fixed using following simple way-

var num = 15.7784514;
Math.floor(num*100)/100;

Results will be 15.77

oms
  • 105
  • 1
  • 2
5

The answers here didn't help me, it kept rounding up or giving me the wrong decimal.

my solution converts your decimal to a string, extracts the characters and then returns the whole thing as a number.

function Dec2(num) {
  num = String(num);
  if(num.indexOf('.') !== -1) {
    var numarr = num.split(".");
    if (numarr.length == 1) {
      return Number(num);
    }
    else {
      return Number(numarr[0]+"."+numarr[1].charAt(0)+numarr[1].charAt(1));
    }
  }
  else {
    return Number(num);
  }  
}

Dec2(99); // 99
Dec2(99.9999999); // 99.99
Dec2(99.35154); // 99.35
Dec2(99.8); // 99.8
Dec2(10265.985475); // 10265.98
David D
  • 1,269
  • 17
  • 22
4

The following code works very good for me:

num.toString().match(/.\*\\..{0,2}|.\*/)[0];
Laazo
  • 467
  • 8
  • 22
MISSIRIA
  • 392
  • 3
  • 6
4

An Easy way to do it is the next but is necessary ensure that the amount parameter is given as a string.

function truncate(amountAsString, decimals = 2){
  var dotIndex = amountAsString.indexOf('.');
  var toTruncate = dotIndex !== -1  && ( amountAsString.length > dotIndex + decimals + 1);
  var approach = Math.pow(10, decimals);
  var amountToTruncate = toTruncate ? amountAsString.slice(0, dotIndex + decimals +1) : amountAsString;  
  return toTruncate
    ?  Math.floor(parseFloat(amountToTruncate) * approach ) / approach
    :  parseFloat(amountAsString);

}

console.log(truncate("7.99999")); //OUTPUT ==> 7.99
console.log(truncate("7.99999", 3)); //OUTPUT ==> 7.999
console.log(truncate("12.799999999999999")); //OUTPUT ==> 7.99
Felipe Santa
  • 369
  • 3
  • 5
4

This worked well for me. I hope it will fix your issues too.

function toFixedNumber(number) {
    const spitedValues = String(number.toLocaleString()).split('.');
    let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
    decimalValue = decimalValue.concat('00').substr(0,2);

    return '$'+spitedValues[0] + '.' + decimalValue;
}

// 5.56789      ---->  $5.56
// 0.342        ---->  $0.34
// -10.3484534  ---->  $-10.34 
// 600          ---->  $600.00

function convertNumber(){
  var result = toFixedNumber(document.getElementById("valueText").value);
  document.getElementById("resultText").value = result;
}


function toFixedNumber(number) {
        const spitedValues = String(number.toLocaleString()).split('.');
        let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
        decimalValue = decimalValue.concat('00').substr(0,2);

        return '$'+spitedValues[0] + '.' + decimalValue;
}
<div>
  <input type="text" id="valueText" placeholder="Input value here..">
  <br>
  <button onclick="convertNumber()" >Convert</button>
  <br><hr>
  <input type="text" id="resultText" placeholder="result" readonly="true">
</div>
Sandaru
  • 61
  • 1
  • 5
3

Here you are. An answer that shows yet another way to solve the problem:

// For the sake of simplicity, here is a complete function:
function truncate(numToBeTruncated, numOfDecimals) {
    var theNumber = numToBeTruncated.toString();
    var pointIndex = theNumber.indexOf('.');
    return +(theNumber.slice(0, pointIndex > -1 ? ++numOfDecimals + pointIndex : undefined));
}

Note the use of + before the final expression. That is to convert our truncated, sliced string back to number type.

Hope it helps!

Jakub Barczyk
  • 565
  • 1
  • 4
  • 11
  • 1
    I like the simplicity of this approach, and I feel that all the solutions that avoid using Maths, are more appropriate for solving this problem. So, the use of slice() etc, is the correct way forward. The only advantage of my method is that it will process numbers passed in that are strings [surrounded by quote marks [single/double]]. For some reason, the function above threw an error in FF, when I did: console.log('truncate("0.85156",2)',truncate("0.85156",2)); – Charles Robertson Jun 02 '17 at 21:24
3

truncate without zeroes

function toTrunc(value,n){  
    return Math.floor(value*Math.pow(10,n))/(Math.pow(10,n));
}

or

function toTrunc(value,n){
    x=(value.toString()+".0").split(".");
    return parseFloat(x[0]+"."+x[1].substr(0,n));
}

test:

toTrunc(17.4532,2)  //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1)   //1.4
toTrunc(.4,2)       //0.4

truncate with zeroes

function toTruncFixed(value,n){
    return toTrunc(value,n).toFixed(n);
}

test:

toTrunc(17.4532,2)  //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1)   //1.4
toTrunc(.4,2)       //0.40
ShAkKiR
  • 863
  • 9
  • 20
3

If you exactly wanted to truncate to 2 digits of precision, you can go with a simple logic:

function myFunction(number) {
  var roundedNumber = number.toFixed(2);
  if (roundedNumber > number)
  {
      roundedNumber = roundedNumber - 0.01;
  }
  return roundedNumber;
}
Deepak
  • 2,660
  • 2
  • 8
  • 23
  • This results in the subtraction problem and generates incorrect results. – Jordan Dec 11 '21 at 15:51
  • The OP has given cases with positive floating point number not integers. Javascript doesn't give correct results when 0.01 is subtracted from a floating point number. For example, if you run 2.37 - 0.01 in your browser console, the answer you will get will be 2.3600000000000003 – Jordan Dec 12 '21 at 12:06
3
function limitDecimalsWithoutRounding(val, decimals){
    let parts = val.toString().split(".");
    return parseFloat(parts[0] + "." + parts[1].substring(0, decimals));
}

var num = parseFloat(15.7784514);
var new_num = limitDecimalsWithoutRounding(num, 2);
Jeff
  • 41
  • 3
2

I used (num-0.05).toFixed(1) to get the second decimal floored.

王景飞
  • 165
  • 1
  • 7
2

It's more reliable to get two floating points without rounding.

Reference Answer

var number = 10.5859;
var fixed2FloatPoints = parseInt(number * 100) / 100;
console.log(fixed2FloatPoints);

Thank You !

Jaydeep Mor
  • 1,690
  • 3
  • 21
  • 39
2

My solution in typescript (can easily be ported to JS):

/**
 * Returns the price with correct precision as a string
 *
 * @param   price The price in decimal to be formatted.
 * @param   decimalPlaces The number of decimal places to use
 * @return  string The price in Decimal formatting.
 */
type toDecimal = (price: number, decimalPlaces?: number) => string;
const toDecimalOdds: toDecimal = (
  price: number,
  decimalPlaces: number = 2,
): string => {
  const priceString: string = price.toString();
  const pointIndex: number = priceString.indexOf('.');

  // Return the integer part if decimalPlaces is 0
  if (decimalPlaces === 0) {
    return priceString.substr(0, pointIndex);
  }

  // Return value with 0s appended after decimal if the price is an integer
  if (pointIndex === -1) {
    const padZeroString: string = '0'.repeat(decimalPlaces);

    return `${priceString}.${padZeroString}`;
  }

  // If numbers after decimal are less than decimalPlaces, append with 0s
  const padZeroLen: number = priceString.length - pointIndex - 1;
  if (padZeroLen > 0 && padZeroLen < decimalPlaces) {
    const padZeroString: string = '0'.repeat(padZeroLen);

    return `${priceString}${padZeroString}`;
  }

  return priceString.substr(0, pointIndex + decimalPlaces + 1);
};

Test cases:

  expect(filters.toDecimalOdds(3.14159)).toBe('3.14');
  expect(filters.toDecimalOdds(3.14159, 2)).toBe('3.14');
  expect(filters.toDecimalOdds(3.14159, 0)).toBe('3');
  expect(filters.toDecimalOdds(3.14159, 10)).toBe('3.1415900000');
  expect(filters.toDecimalOdds(8.2)).toBe('8.20');

Any improvements?

VPaul
  • 1,005
  • 11
  • 21
2

Another solution, that truncates and round:

function round (number, decimals, truncate) {
    if (truncate) {
        number = number.toFixed(decimals + 1);
        return parseFloat(number.slice(0, -1));
    }

    var n = Math.pow(10.0, decimals);
    return Math.round(number * n) / n;
};
Beto Neto
  • 3,962
  • 7
  • 47
  • 81
1

Roll your own toFixed function: for positive values Math.floor works fine.

function toFixed(num, fixed) {
    fixed = fixed || 0;
    fixed = Math.pow(10, fixed);
    return Math.floor(num * fixed) / fixed;
}

For negative values Math.floor is round of the values. So you can use Math.ceil instead.

Example,

Math.ceil(-15.778665 * 10000) / 10000 = -15.7786
Math.floor(-15.778665 * 10000) / 10000 = -15.7787 // wrong.
Tom
  • 26,212
  • 21
  • 100
  • 111
  • 5
    So many of these answers have a multiplication inside a Math.floor() function. This will fail for some numbers! Floating point arithmetic is not accurate and you need to use different methods. – Nico Westerdale Nov 04 '16 at 15:35
1

Gumbo's second solution, with the regular expression, does work but is slow because of the regular expression. Gumbo's first solution fails in certain situations due to imprecision in floating points numbers. See the JSFiddle for a demonstration and a benchmark. The second solution takes about 1636 nanoseconds per call on my current system, Intel Core i5-2500 CPU at 3.30 GHz.

The solution I've written involves adding a small compensation to take care of floating point imprecision. It is basically instantaneous, i.e. on the order of nanoseconds. I clocked 2 nanoseconds per call but the JavaScript timers are not very precise or granular. Here is the JS Fiddle and the code.

function toFixedWithoutRounding (value, precision)
{
    var factorError = Math.pow(10, 14);
    var factorTruncate = Math.pow(10, 14 - precision);
    var factorDecimal = Math.pow(10, precision);
    return Math.floor(Math.floor(value * factorError + 1) / factorTruncate) / factorDecimal;
}

var values = [1.1299999999, 1.13, 1.139999999, 1.14, 1.14000000001, 1.13 * 100];

for (var i = 0; i < values.length; i++)
{
    var value = values[i];
    console.log(value + " --> " + toFixedWithoutRounding(value, 2));
}

for (var i = 0; i < values.length; i++)
{
    var value = values[i];
    console.log(value + " --> " + toFixedWithoutRounding(value, 4));
}

console.log("type of result is " + typeof toFixedWithoutRounding(1.13 * 100 / 100, 2));

// Benchmark
var value = 1.13 * 100;
var startTime = new Date();
var numRun = 1000000;
var nanosecondsPerMilliseconds = 1000000;

for (var run = 0; run < numRun; run++)
    toFixedWithoutRounding(value, 2);

var endTime = new Date();
var timeDiffNs = nanosecondsPerMilliseconds * (endTime - startTime);
var timePerCallNs = timeDiffNs / numRun;
console.log("Time per call (nanoseconds): " + timePerCallNs);
Daniel Barbalace
  • 1,197
  • 1
  • 17
  • 10
1

Already there are some suitable answer with regular expression and arithmetic calculation, you can also try this

function myFunction() {
    var str = 12.234556; 
    str = str.toString().split('.');
    var res = str[1].slice(0, 2);
    document.getElementById("demo").innerHTML = str[0]+'.'+res;
}

// output: 12.23
a--m
  • 4,716
  • 1
  • 39
  • 59
ANIK ISLAM SHOJIB
  • 3,002
  • 1
  • 27
  • 36
1

Building on David D's answer:

function NumberFormat(num,n) {
  var num = (arguments[0] != null) ? arguments[0] : 0;
  var n = (arguments[1] != null) ? arguments[1] : 2;
  if(num > 0){
    num = String(num);
    if(num.indexOf('.') !== -1) {
      var numarr = num.split(".");
      if (numarr.length > 1) {
        if(n > 0){
          var temp = numarr[0] + ".";
          for(var i = 0; i < n; i++){
            if(i < numarr[1].length){
              temp += numarr[1].charAt(i);
            }
          }
          num = Number(temp);
        }
      }
    }
  }
  return Number(num);
}

console.log('NumberFormat(123.85,2)',NumberFormat(123.85,2));
console.log('NumberFormat(123.851,2)',NumberFormat(123.851,2));
console.log('NumberFormat(0.85,2)',NumberFormat(0.85,2));
console.log('NumberFormat(0.851,2)',NumberFormat(0.851,2));
console.log('NumberFormat(0.85156,2)',NumberFormat(0.85156,2));
console.log('NumberFormat(0.85156,4)',NumberFormat(0.85156,4));
console.log('NumberFormat(0.85156,8)',NumberFormat(0.85156,8));
console.log('NumberFormat(".85156",2)',NumberFormat(".85156",2));
console.log('NumberFormat("0.85156",2)',NumberFormat("0.85156",2));
console.log('NumberFormat("1005.85156",2)',NumberFormat("1005.85156",2));
console.log('NumberFormat("0",2)',NumberFormat("0",2));
console.log('NumberFormat("",2)',NumberFormat("",2));
console.log('NumberFormat(85156,8)',NumberFormat(85156,8));
console.log('NumberFormat("85156",2)',NumberFormat("85156",2));
console.log('NumberFormat("85156.",2)',NumberFormat("85156.",2));

// NumberFormat(123.85,2) 123.85
// NumberFormat(123.851,2) 123.85
// NumberFormat(0.85,2) 0.85
// NumberFormat(0.851,2) 0.85
// NumberFormat(0.85156,2) 0.85
// NumberFormat(0.85156,4) 0.8515
// NumberFormat(0.85156,8) 0.85156
// NumberFormat(".85156",2) 0.85
// NumberFormat("0.85156",2) 0.85
// NumberFormat("1005.85156",2) 1005.85
// NumberFormat("0",2) 0
// NumberFormat("",2) 0
// NumberFormat(85156,8) 85156
// NumberFormat("85156",2) 85156
// NumberFormat("85156.",2) 85156
Charles Robertson
  • 1,760
  • 16
  • 21
1

Here is what is did it with string

export function withoutRange(number) {
  const str = String(number);
  const dotPosition = str.indexOf('.');
  if (dotPosition > 0) {
    const length = str.substring().length;
    const end = length > 3 ? 3 : length;
    return str.substring(0, dotPosition + end);
  }
  return str;
}
Kishan Vaghela
  • 7,678
  • 5
  • 42
  • 67
1

All these answers seem a bit complicated. I would just subtract 0.5 from your number and use toFixed().

Sean Mayes
  • 158
  • 10
1

Taking the knowledge from all the previous answers combined,

this is what I came up with as a solution:

function toFixedWithoutRounding(num, fractionDigits) {
  if ((num > 0 && num < 0.000001) || (num < 0 && num > -0.000001)) {
    // HACK: below this js starts to turn numbers into exponential form like 1e-7.
    // This gives wrong results so we are just changing the original number to 0 here
    // as we don't need such small numbers anyway.
    num = 0;
  }
  const re = new RegExp('^-?\\d+(?:\.\\d{0,' + (fractionDigits || -1) + '})?');
  return Number(num.toString().match(re)[0]).toFixed(fractionDigits);
}
patotoma
  • 1,069
  • 2
  • 11
  • 15
1
function toFixed(num, fixed) {
    fixed = fixed || 0;
    var front = Math.floor(num);
    var back = 0;
    for (var i = 1; i <= fixed; i++) {
        var value = Math.floor(num * Math.pow(10, i)) % 10;
        back += value / Math.pow(10, i);
    }
    return front + back;
}
Terry Tan
  • 421
  • 5
  • 12
1

UPDATED JUNE 2021

this will fix any number with the given length without rounding

let FixWithoutRounding = (v, l) => {
      const intPart = Math.trunc(v).toString()
      const fractionPart = v.toString().slice(v.toString().indexOf('.') + 1)
      if (fractionPart.length > l) {
        return Number(intPart.concat('.', fractionPart.slice(0, l)))
      } else {
        const padded = intPart.concat('.', fractionPart.padEnd(l, '0'))
        return padded
      }
    }

console.log(FixWithoutRounding(123.123, 12))
Arslan
  • 67
  • 1
  • 5
1

I was facing the same problem, and decided using string manipulation in TS.

If not enough decimals, it will return the original value

const getDecimalsWithoutRounding = (value: number, numberOfDecimals: number) => {
  const stringValue: string = value?.toString();
  const dotIdx: number = stringValue?.indexOf('.');
  if (dotIdx) {
    return parseFloat(stringValue.slice(0, dotIdx + numberOfDecimals + 1));
  } else {
    return value;
  }
};

console.log(getDecimalsWithoutRounding(3.34589, 2)); /// 3.34
console.log(getDecimalsWithoutRounding(null, 2));  ///null
console.log(getDecimalsWithoutRounding(55.123456789, 5)); /// 55.12345
console.log(getDecimalsWithoutRounding(10, 2));  /// 10
console.log(getDecimalsWithoutRounding(10.6, 5)); /// 10.6


0

The most efficient solution (for 2 fraction digits) is to subtract 0.005 before calling toFixed()

function toFixed2( num ) { return (num-0.005).toFixed(2) }

Negative numbers will be rounded down too (away from zero). The OP didn't tell anything about negative numbers.

Wiimm
  • 2,971
  • 1
  • 15
  • 25
  • It works. The issue here is, that `4.27` does not exists and is rounded to `4.26999999999999957`. And rounding down this number is `4.26`. Try `(4.27).toPrecision(18)` to verify. – Wiimm May 03 '21 at 07:26
  • In general, most numbers has no exact representation as computer number (IEEE 754). So every input is rounded to the nearest possible value first. And here 0.005 is also rounded to a value slightly larger than 0.005. And so each calculation step make a floating point number more inexact. – Wiimm May 03 '21 at 07:50
0

I know there are already few working examples, but I think it's worth to propose my String.toFixed equivalent, some may find it helpful.

That's my toFixed alternative, that don't round numbers, just truncates it or adds zeroes according to given precision. For extra long number it uses JS build-in rounding when precision is to long. Function works for all problematic number I've found on stack.

function toFixedFixed(value, precision = 0) {
    let stringValue = isNaN(+value) ? '0' : String(+value);

    if (stringValue.indexOf('e') > -1 || stringValue === 'Infinity' || stringValue === '-Infinity') {
        throw new Error('To large number to be processed');
    }

    let [ beforePoint, afterPoint ] = stringValue.indexOf('.') > -1 ? stringValue.split('.') : [ stringValue, ''];

    // Force automatic rounding for some long real numbers that ends with 99X, by converting it to string, cutting off last digit, then adding extra nines and casting it on number again
    // e.g. 2.0199999999999996: +('2.019999999999999' + '9999') will give 2.02
    if (stringValue.length >= 17 && afterPoint.length > 2 && +afterPoint.substr(afterPoint.length - 3) > 995) {
        stringValue = String(+(stringValue.substr(0, afterPoint.length - 1) + '9'.repeat(stringValue.split('.').shift().length + 4)));
        [ beforePoint, afterPoint ] = String(stringValue).indexOf('.') > -1 ? stringValue.split('.') : [ stringValue, ''];
    }

    if (precision === 0) {
        return beforePoint;
    } else if (afterPoint.length > precision) {
        return `${beforePoint}.${afterPoint.substr(0, precision)}`;
    } else {
        return `${beforePoint}.${afterPoint}${'0'.repeat(precision - afterPoint.length)}`;
    }
}

Keep in mind that precision may not be handled properly for numbers of length 18 and greater, e.g. 64-bit Chrome will round it or add "e+" / "e-" to keep number's length at 18.

If you want to perform operations on real numbers it's safer to multiply it by Math.sqrt(10, precision) first, make the calculations, then dive result by multiplier's value.

Example:

0.06 + 0.01 is 0.06999999999999999, and every formatting function that's not rounding will truncate it to 0.06 for precision 2.

But if you'll perform same operation with multiplier&divider: (0.06 * 100 + 0.01 * 100) / 100, you'll get 0.07.

That's why it's so important to use such multiplier/divider when dealing with real numbers in javascript, especially when you're calculating money...

MagyaDEV
  • 375
  • 3
  • 8
0

In order to collaborate, there is a solution that I had to use with Bitcoin math operations. The point is that Bitcoin uses 8 decimal numbers, and we needed no round.

So, I did this:

  • do the calculation;

  • take the value and set 9 decimal houses

    value = value.toFixed(9);

-take the substring cutting off the last decimal number:

value = value.substring(0, value.length - 1);

No. This is not elegant, but it's a solution.

Michel Fernandes
  • 1,187
  • 9
  • 8
0
function FixWithoutRounding(number, digits) {
  var gbZero = '0000000000';
  var subNumber = number.toString().split('.');

  if (subNumber.length === 1)
    return [subNumber[0], '.', '0000'].join('');

  var result = '';
  if (subNumber[1].length > digits) {
    result = subNumber[1].substring(0, digits);
  } else {
    result = subNumber[1] + gbZero.substring(0, digits - subNumber[1].length);
  }

  return [subNumber[0], '.', result].join('');

}
The Best
  • 105
  • 1
  • 1
  • 7
-1

Here is another one variant to save .toFixed([digits]) functional without rounding float variable:

Number.prototype.toRealFixed = function(digits) {
    return Math.floor(this.valueOf() * Math.pow(10, digits)) / Math.pow(10, digits);
};

And calling:

var float_var = 0.02209062;
float_var.toRealFixed();
AlexxKur
  • 1
  • 2
-1

const toFixed = (value) => value.toString().slice(0,5);

Artem Bochkarev
  • 1,242
  • 13
  • 23
  • 3
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value – Igor F. Feb 19 '20 at 13:39
-1

a simple solution

const toFixedNoRounding = (value, digits) => {
  const factor = Math.pow(10, digits);

  return Math.trunc(value * factor) / factor;
};
Lahcen
  • 1,231
  • 11
  • 15
-2

Thanks Martin Varmus

function floorFigure(figure, decimals){
     if (!decimals) decimals = 2;
     var d = Math.pow(10,decimals);
     return ((figure*d)/d).toFixed(decimals);
};

floorFigure(123.5999)    =>   "123.59"
floorFigure(123.5999, 3) =>   "123.599"

I make a simple update and I got proper rounding. The update is following line

return ((figure*d)/d).toFixed(decimals);

remove parseInt() function

Jakir Hosen Khan
  • 1,498
  • 1
  • 14
  • 17
  • Tweaks to another another answer tend to do better as comments, especially because the OP was looking for answers with no rounding. – Brad Koch Apr 23 '13 at 14:27
  • 1
    When I run your function, I get `floorFigure(123.5999) => "123.60"` and `floorFigure(123.5999, 3) => "123.600"`. Care to clarify? – Brad Koch Apr 23 '13 at 14:29
  • @BradKoch the one with parseInt is proper, this is invalid. – Nijikokun Feb 03 '15 at 00:12