Truncate (not round off) decimal numbers in javascript

JavascriptFloating PointFloating Accuracy

Javascript Problem Overview


I am trying to truncate decimal numbers to decimal places. Something like this:

5.467   -> 5.46  
985.943 -> 985.94

toFixed(2) does just about the right thing but it rounds off the value. I don't need the value rounded off. Hope this is possible in javascript.

Javascript Solutions


Solution 1 - Javascript

Dogbert's answer is good, but if your code might have to deal with negative numbers, Math.floor by itself may give unexpected results.

E.g. Math.floor(4.3) = 4, but Math.floor(-4.3) = -5

Use a helper function like this one instead to get consistent results:

truncateDecimals = function (number) {
    return Math[number < 0 ? 'ceil' : 'floor'](number);
};

// Applied to Dogbert's answer:
var a = 5.467;
var truncated = truncateDecimals(a * 100) / 100; // = 5.46

Here's a more convenient version of this function:

truncateDecimals = function (number, digits) {
    var multiplier = Math.pow(10, digits),
        adjustedNum = number * multiplier,
        truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);

    return truncatedNum / multiplier;
};

// Usage:
var a = 5.467;
var truncated = truncateDecimals(a, 2); // = 5.46

// Negative digits:
var b = 4235.24;
var truncated = truncateDecimals(b, -2); // = 4200

If that isn't desired behaviour, insert a call to Math.abs on the first line:

var multiplier = Math.pow(10, Math.abs(digits)),

EDIT: shendz correctly points out that using this solution with a = 17.56 will incorrectly produce 17.55. For more about why this happens, read What Every Computer Scientist Should Know About Floating-Point Arithmetic. Unfortunately, writing a solution that eliminates all sources of floating-point error is pretty tricky with javascript. In another language you'd use integers or maybe a Decimal type, but with javascript...

This solution should be 100% accurate, but it will also be slower:

function truncateDecimals (num, digits) {
    var numS = num.toString(),
        decPos = numS.indexOf('.'),
        substrLength = decPos == -1 ? numS.length : 1 + decPos + digits,
        trimmedResult = numS.substr(0, substrLength),
        finalResult = isNaN(trimmedResult) ? 0 : trimmedResult;

    return parseFloat(finalResult);
}

For those who need speed but also want to avoid floating-point errors, try something like BigDecimal.js. You can find other javascript BigDecimal libraries in this SO question: "Is there a good Javascript BigDecimal library?" and here's a good blog post about math libraries for Javascript

Solution 2 - Javascript

upd:

So, after all it turned out, rounding bugs will always haunt you, no matter how hard you try to compensate them. Hence the problem should be attacked by representing numbers exactly in decimal notation.

Number.prototype.toFixedDown = function(digits) {
    var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),
        m = this.toString().match(re);
    return m ? parseFloat(m[1]) : this.valueOf();
};

[   5.467.toFixedDown(2),
    985.943.toFixedDown(2),
    17.56.toFixedDown(2),
    (0).toFixedDown(1),
    1.11.toFixedDown(1) + 22];

// [5.46, 985.94, 17.56, 0, 23.1]

Old error-prone solution based on compilation of others':

Number.prototype.toFixedDown = function(digits) {
  var n = this - Math.pow(10, -digits)/2;
  n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56"
  return n.toFixed(digits);
}

Solution 3 - Javascript

var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46

Solution 4 - Javascript

You can fix the rounding by subtracting 0.5 for toFixed, e.g.

(f - 0.005).toFixed(2)

Solution 5 - Javascript

Consider taking advantage of the double tilde: ~~.

Take in the number. Multiply by significant digits after the decimal so that you can truncate to zero places with ~~. Divide that multiplier back out. Profit.

function truncator(numToTruncate, intDecimalPlaces) {    
    var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better
    return ~~(numToTruncate * numPower)/numPower;
}

I'm trying to resist wrapping the ~~ call in parens; order of operations should make that work correctly, I believe.

alert(truncator(5.1231231, 1)); // is 5.1

alert(truncator(-5.73, 1)); // is -5.7

alert(truncator(-5.73, 0)); // is -5

JSFiddle link.

EDIT: Looking back over, I've unintentionally also handled cases to round off left of the decimal as well.

alert(truncator(4343.123, -2)); // gives 4300.

The logic's a little wacky looking for that usage, and may benefit from a quick refactor. But it still works. Better lucky than good.

Solution 6 - Javascript

Nice one-line solution:

function truncate (num, places) {
  return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places);
}

Then call it with:

truncate(3.5636232, 2); // returns 3.56
truncate(5.4332312, 3); // returns 5.433
truncate(25.463214, 4); // returns 25.4632

Solution 7 - Javascript

I thought I'd throw in an answer using | since it is simple and works well.

truncate = function(number, places) {
  var shift = Math.pow(10, places);

  return ((number * shift) | 0) / shift;
};

Solution 8 - Javascript

Truncate using bitwise operators:

~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439

Solution 9 - Javascript

@Dogbert's answer can be improved with Math.trunc, which truncates instead of rounding.

> There is a difference between rounding and truncating. Truncating is > clearly the behaviour this question is seeking. If I call > truncate(-3.14) and receive -4 back, I would definitely call that > undesirable. – @NickKnowlson

var a = 5.467;
var truncated = Math.trunc(a * 100) / 100; // = 5.46

var a = -5.467;
var truncated = Math.trunc(a * 100) / 100; // = -5.46

Solution 10 - Javascript

I wrote an answer using a shorter method. Here is what I came up with

function truncate(value, precision) {
    var step = Math.pow(10, precision || 0);
    var temp = Math.trunc(step * value);

    return temp / step;
}

The method can be used like so

truncate(132456.25456789, 5)); // Output: 132456.25456
truncate(132456.25456789, 3)); // Output: 132456.254
truncate(132456.25456789, 1)); // Output: 132456.2   
truncate(132456.25456789));    // Output: 132456

Or, if you want a shorter syntax, here you go

function truncate(v, p) {
    var s = Math.pow(10, p || 0);
    return Math.trunc(s * v) / s;
}

Solution 11 - Javascript

I think this function could be a simple solution:

function trunc(decimal,n=2){
  let x = decimal + ''; // string 
  return x.lastIndexOf('.')>=0?parseFloat(x.substr(0,x.lastIndexOf('.')+(n+1))):decimal; // You can use indexOf() instead of lastIndexOf()
}

console.log(trunc(-241.31234,2));
console.log(trunc(241.312,5));
console.log(trunc(-241.233));
console.log(trunc(241.2,0));  
console.log(trunc(241));

Solution 12 - Javascript

Number.prototype.trim = function(decimals) {
    var s = this.toString();
    var d = s.split(".");
    d[1] = d[1].substring(0, decimals);
    return parseFloat(d.join("."));
}

console.log((5.676).trim(2)); //logs 5.67

Solution 13 - Javascript

I found a problem: considering the next situation: 2.1 or 1.2 or -6.4

What if you want always 3 decimals or two or wharever, so, you have to complete the leading zeros to the right

// 3 decimals numbers
0.5 => 0.500

// 6 decimals
0.1 => 0.10000

// 4 decimales
-2.1 => -2.1000

// truncate to 3 decimals
3.11568 => 3.115

This is the fixed function of Nick Knowlson

function truncateDecimals (num, digits) 
{
    var numS = num.toString();
    var decPos = numS.indexOf('.');
    var substrLength = decPos == -1 ? numS.length : 1 + decPos + digits;
    var trimmedResult = numS.substr(0, substrLength);
    var finalResult = isNaN(trimmedResult) ? 0 : trimmedResult;
    
    // adds leading zeros to the right
    if (decPos != -1){
        var s = trimmedResult+"";
        decPos = s.indexOf('.');
        var decLength = s.length - decPos;
       
            while (decLength <= digits){
                s = s + "0";
                decPos = s.indexOf('.');
                decLength = s.length - decPos;
                substrLength = decPos == -1 ? s.length : 1 + decPos + digits;
            };
        finalResult = s;
    }
    return finalResult;
};

https://jsfiddle.net/huttn155/7/

Solution 14 - Javascript

The answer by @kirilloid seems to be the correct answer, however, the main code needs to be updated. His solution doesn't take care of negative numbers (which someone did mention in the comment section but has not been updated in the main code).

Updating that to a complete final tested solution:

Number.prototype.toFixedDown = function(digits) {
    var re = new RegExp("([-]*\\d+\\.\\d{" + digits + "})(\\d)"),
    m = this.toString().match(re);
    return m ? parseFloat(m[1]) : this.valueOf();
};

Sample Usage:

var x = 3.1415629;
Logger.log(x.toFixedDown(2)); //or use whatever you use to log

Fiddle: JS Number Round down

PS: Not enough repo to comment on that solution.

Solution 15 - Javascript

function toFixed(number, digits) {
    var reg_ex = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)")
    var array = number.toString().match(reg_ex);
    return array ? parseFloat(array[1]) : number.valueOf()
}

var test = 10.123456789
var __fixed = toFixed(test, 6)
console.log(__fixed)
// => 10.123456

Solution 16 - Javascript

Here is simple but working function to truncate number upto 2 decimal places.

           function truncateNumber(num) {
                var num1 = "";
                var num2 = "";
                var num1 = num.split('.')[0];
                num2 = num.split('.')[1];
                var decimalNum = num2.substring(0, 2);
                var strNum = num1 +"."+ decimalNum;
                var finalNum = parseFloat(strNum);
                return finalNum;
            }

Solution 17 - Javascript

The resulting type remains a number...

/* Return the truncation of n wrt base */
var trunc = function(n, base) {
    n = (n / base) | 0;
    return base * n;
};
var t = trunc(5.467, 0.01);

Solution 18 - Javascript

Lodash has a few Math utility methods that can round, floor, and ceil a number to a given decimal precision. This leaves off trailing zeroes.

They take an interesting approach, using the exponent of a number. Apparently this avoids rounding issues.

(Note: func is Math.round or ceil or floor in the code below)

// Shift with exponential notation to avoid floating-point issues.
var pair = (toString(number) + 'e').split('e'),
    value = func(pair[0] + 'e' + (+pair[1] + precision));

pair = (toString(value) + 'e').split('e');
return +(pair[0] + 'e' + (+pair[1] - precision));

Link to the source code

Solution 19 - Javascript

I'm a bit confused as to why there are so many different answers to such a fundamentally simple question; there are only two approaches which I saw which seemed to be worth looking at. I did a quick benchmark to see the speed difference using https://jsbench.me/.

This is the solution which is currently (9/26/2020) flagged as the answer:

function truncate(n, digits) {
    var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),
        m = n.toString().match(re);
    return m ? parseFloat(m[1]) : n.valueOf();
};

[   truncate(5.467,2),
    truncate(985.943,2),
    truncate(17.56,2),
    truncate(0, 1),
    truncate(1.11, 1) + 22];

However, this is doing string and regex stuff, which is usually not very efficient, and there is a Math.trunc function which does exactly what the OP wants just with no decimals. Therefore, you can easily use that plus a little extra arithmetic to get the same thing.

Here is another solution I found on this thread, which is the one I would use:

function truncate(n, digits) {
    var step = Math.pow(10, digits || 0);
    var temp = Math.trunc(step * n);

    return temp / step;
}

[   truncate(5.467,2),
    truncate(985.943,2),
    truncate(17.56,2),
    truncate(0, 1),
    truncate(1.11, 1) + 22];
    

The first method is "99.92% slower" than the second, so the second is definitely the one I would recommend using.

Okay, back to finding other ways to avoid work...

screenshot of the benchmark

Solution 20 - Javascript

Here my take on the subject:

convert.truncate = function(value, decimals) {
  decimals = (decimals === undefined ? 0 : decimals);
  return parseFloat((value-(0.5/Math.pow(10, decimals))).toFixed(decimals),10);
};

It's just a slightly more elaborate version of

(f - 0.005).toFixed(2)

Solution 21 - Javascript

The one that is mark as the solution is the better solution I been found until today, but has a serious problem with 0 (for example, 0.toFixedDown(2) gives -0.01). So I suggest to use this:

Number.prototype.toFixedDown = function(digits) {
  if(this == 0) {
    return 0;
  }
  var n = this - Math.pow(10, -digits)/2;
  n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56"
  return n.toFixed(digits);
}

Solution 22 - Javascript

Here is what I use:

var t = 1;
for (var i = 0; i < decimalPrecision; i++)
    t = t * 10;
    
var f = parseFloat(value);
return (Math.floor(f * t)) / t;

Solution 23 - Javascript

const TO_FIXED_MAX = 100;
  
function truncate(number, decimalsPrecison) {
  // make it a string with precision 1e-100
  number = number.toFixed(TO_FIXED_MAX);

  // chop off uneccessary digits
  const dotIndex = number.indexOf('.');
  number = number.substring(0, dotIndex + decimalsPrecison + 1);

  // back to a number data type (app specific)
  return Number.parseFloat(number);
}

// example
truncate(0.00000001999, 8);
0.00000001

works with:

  • negative numbers
  • very small numbers (Number.EPSILON precision)

Solution 24 - Javascript

You can work with strings. It Checks if '.' exists, and then removes part of string.

truncate (7.88, 1) --> 7.8

truncate (7.889, 2) --> 7.89

truncate (-7.88, 1 ) --> -7.88

function  truncate(number, decimals) {
    const tmp = number + '';
    if (tmp.indexOf('.') > -1) {
        return +tmp.substr(0 , tmp.indexOf('.') + decimals+1 );
    } else {
        return +number
    }
 }

Solution 25 - Javascript

just to point out a simple solution that worked for me

convert it to string and then regex it...

var number = 123.45678;
var number_s = '' + number;
var number_truncated_s = number_s.match(/\d*\.\d{4}/)[0]
var number_truncated = parseFloat(number_truncated_s)

It can be abbreviated to

var number_truncated = parseFloat(('' + 123.4568908).match(/\d*\.\d{4}/)[0])

Solution 26 - Javascript

Here is an ES6 code which does what you want

const truncateTo = (unRouned, nrOfDecimals = 2) => {
      const parts = String(unRouned).split(".");

      if (parts.length !== 2) {
          // without any decimal part
        return unRouned;
      }

      const newDecimals = parts[1].slice(0, nrOfDecimals),
        newString = `${parts[0]}.${newDecimals}`;

      return Number(newString);
    };

// your examples 

 console.log(truncateTo(5.467)); // ---> 5.46

 console.log(truncateTo(985.943)); // ---> 985.94

// other examples 

 console.log(truncateTo(5)); // ---> 5

 console.log(truncateTo(-5)); // ---> -5

 console.log(truncateTo(-985.943)); // ---> -985.94

Solution 27 - Javascript

Suppose you want to truncate number x till n digits.

> Math.trunc(x * pow(10,n))/pow(10,n);

Solution 28 - Javascript

function trunc(num, dec) {
  const pow = 10 ** dec
  return Math.trunc(num * pow) / pow
}

// ex.
trunc(4.9634, 1) // 4.9
trunc(4.9634, 2) // 4.96
trunc(-4.9634, 1) // -4.9

Solution 29 - Javascript

Number.prototype.truncate = function(places) {
  var shift = Math.pow(10, places);

  return Math.trunc(this * shift) / shift;
};

Solution 30 - Javascript

  function toFix(num,n)
    {
    beforeDecimal=num.toString().split(".",[2])[0];
    afterDecimal=num.toString().split(".",[2])[1];
    updateAfterDecimal="";
    if(afterDecimal != undefined && afterDecimal.length >= n )
        updateAfterDecimal =afterDecimal.slice(0,n);
    if(afterDecimal != undefined && afterDecimal.length < n )
        updateAfterDecimal= afterDecimal.padEnd(n,"0");
    if(afterDecimal== undefined)
        updateAfterDecimal=updateAfterDecimal.padEnd(n,"0");
    console.log(`${beforeDecimal}.${updateAfterDecimal}`);
    }
    toFix(5.12365889,5); 

Solution 31 - Javascript

enter code here

 let number=5.467;// we want to truncate into 5.46
     let result=+number.toString().split("").splice(0,4).join('');
     console.log(result);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionkcssmView Question on Stackoverflow
Solution 1 - JavascriptNick KnowlsonView Answer on Stackoverflow
Solution 2 - JavascriptkirilloidView Answer on Stackoverflow
Solution 3 - JavascriptDogbertView Answer on Stackoverflow
Solution 4 - JavascriptRichardTheKiwiView Answer on Stackoverflow
Solution 5 - JavascriptruffinView Answer on Stackoverflow
Solution 6 - JavascriptMeestorHokView Answer on Stackoverflow
Solution 7 - JavascriptDaniel X MooreView Answer on Stackoverflow
Solution 8 - JavascriptJohn StricklerView Answer on Stackoverflow
Solution 9 - JavascriptzurfyxView Answer on Stackoverflow
Solution 10 - Javascriptuser8249395View Answer on Stackoverflow
Solution 11 - JavascriptJulio Cesar Cervantes MartinezView Answer on Stackoverflow
Solution 12 - JavascriptMax ZlotskiyView Answer on Stackoverflow
Solution 13 - JavascriptjuanpscottoView Answer on Stackoverflow
Solution 14 - JavascriptProgWizView Answer on Stackoverflow
Solution 15 - JavascriptFlavioView Answer on Stackoverflow
Solution 16 - JavascriptRohannGView Answer on Stackoverflow
Solution 17 - JavascriptBob LyonView Answer on Stackoverflow
Solution 18 - JavascriptMatthiasView Answer on Stackoverflow
Solution 19 - JavascripttaxilianView Answer on Stackoverflow
Solution 20 - JavascriptopensasView Answer on Stackoverflow
Solution 21 - JavascriptSebastián RojasView Answer on Stackoverflow
Solution 22 - JavascriptSteveView Answer on Stackoverflow
Solution 23 - JavascriptgivanseView Answer on Stackoverflow
Solution 24 - JavascriptDaniel Alejandro Lima MonzonView Answer on Stackoverflow
Solution 25 - JavascriptSergio CampamáView Answer on Stackoverflow
Solution 26 - JavascriptCristian SimaView Answer on Stackoverflow
Solution 27 - JavascriptMohit VachhaniView Answer on Stackoverflow
Solution 28 - Javascriptwebm94View Answer on Stackoverflow
Solution 29 - JavascriptDercniView Answer on Stackoverflow
Solution 30 - JavascriptAnkur144View Answer on Stackoverflow
Solution 31 - JavascriptElias kibretView Answer on Stackoverflow