Truncate (not round off) decimal numbers in javascript

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.

186290 次浏览
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46

你可以修正四舍五入减去0.5的固定,例如。

(f - 0.005).toFixed(2)

upd:

所以,无论你多么努力地去补偿它们,最终结果是,舍入错误总是困扰着你。因此,应该用十进制表示法精确地表示数字来解决这个问题。

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]

基于汇编其他人的旧的容易出错的解决方案:

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

Dogbert 的答案是好的,但是如果您的代码可能必须处理负数,那么 Math.floor本身可能会产生意想不到的结果。

例如 Math.floor(4.3) = 4,但是 Math.floor(-4.3) = -5

使用类似这样的辅助函数可以得到一致的结果:

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

下面是这个函数的一个更方便的版本:

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)),

编辑: shendz 正确地指出,在 a = 17.56中使用这种解决方案将不正确地产生 17.55。有关为什么会发生这种情况的更多信息,请阅读 关于浮点算法,每个计算机科学家都应该知道什么。不幸的是,使用 javascript 编写一个消除所有浮点错误源的解决方案是相当棘手的。在另一种语言中,您可能会使用整数或 Decimal 类型,但是对于 javascript..。

This solution 应该是 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);
}

对于那些需要速度但又想避免浮点错误的人,可以尝试类似于 BigDecimal.js的东西。您可以在这个 SO 问题中找到其他的 javascript BigDecimal 库: “有好的 Javascript BigDecimal 库吗?”,这里有一篇关于 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);
};

这只是一个稍微复杂一点的版本

(f - 0.005).toFixed(2)

考虑 利用双波浪的优势: ~~

记住这个数字。乘以小数后面的有效数字,这样你就可以用 abc0从1乘到0。把那个乘数除回去。利润。

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

我试图避免使用括号来包装 ~~调用; 我相信,操作顺序应该能够使其正确工作。

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

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

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

JSFiddle 链接。

编辑: 回顾过去,我无意中也处理了小数点左边的情况。

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

寻找这种用法的逻辑有点古怪,可能会从快速重构中获益。但它仍然有效。幸运总比好运好。

只是为了指出一个对我有用的简单解决方案

转换成字符串,然后正则表达式。

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)

可以缩写为

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

我想我应该使用 |来回答这个问题,因为它很简单,而且工作得很好。

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


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

标记为解决方案的那个是我今天发现的更好的解决方案,但是在0(例如,0)方面有一个严重的问题。ToFixedDown (2)给出 -0.01)。所以我建议用这个:

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

以下是我使用的方法:

var t = 1;
for (var i = 0; i < decimalPrecision; i++)
t = t * 10;


var f = parseFloat(value);
return (Math.floor(f * t)) / t;

这里有一个简单但有效的函数,可以将数字截断到小数点后2位。

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

我发现了一个问题: 考虑下一种情况: 2.1、1.2或 -6.4

如果你总是想要3个小数点或者2个小数点或者其他什么的,那么,你必须完成右边前面的0

// 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

这是尼克 · 诺尔森的固定功能

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/

结果类型仍然是一个数字..。

/* 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);

不错的一句话解决方案:

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

然后说:

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

这里有一个 ES6代码,可以做你想做的事情

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

使用位运算符截断:

~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439
Number.prototype.truncate = function(places) {
var shift = Math.pow(10, places);


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

@ Dogbert 的答案可以用 Math.trunc改进,它是截断而不是舍入。

舍入和截断是有区别的。截断是 很明显,这个问题正在寻找的行为。如果我打电话 截断(-3.14)并接收 -4返回,我肯定会称之为 不受欢迎

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

@ kirilloid 给出的答案似乎是正确的,然而,主代码需要更新。他的解决方案没有考虑负数(有人在注释部分提到了负数,但在主代码中没有更新)。

将其更新为一个完整的最终测试解决方案:

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

用法示例:

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

Fiddle: JS 数字四舍五入

附注: 没有足够的回购来评论这个解决方案。

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

我认为这个函数可能是一个简单的解决方案:

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

Lodash 有一些数学实用程序方法,它们可以将一个数字 圆的地板细胞转换为给定的十进制精度。这样就没有后面的零了。

他们采取了一个有趣的方法,使用一个数的指数。显然,这避免了舍入问题。

(注意: 在下面的代码中,funcMath.roundceilfloor)

// 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));

链接到源代码

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

该方法可以这样使用

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

或者,如果你想要一个更短的语法,这就是了

function truncate(v, p) {
var s = Math.pow(10, p || 0);
return Math.trunc(s * v) / s;
}
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:

  • 负数
  • 非常小的数字(数字. EPSILON 精度)

你可以用绳子工作。 它检查“ .”是否存在,然后删除部分字符串。

截断(7.88,1)-> 7.8

截断(7.889,2)—— > 7.89

截断(-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
}
}

我有点困惑,为什么这么简单的问题有这么多不同的答案; 我看到的似乎只有两种值得研究的方法。我使用 https://jsbench.me/做了一个快速基准测试来看速度差异。

这就是目前(2020年9月26日)被标记为答案的解决方案:

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

然而,这是做字符串和正则表达式的东西,这通常是不太有效的,有一个 Math.trunc 函数,它做的 没错什么 OP 想只是没有小数。因此,您可以很容易地使用它再加上一点额外的算术来得到相同的结果。

下面是我在这个帖子中找到的另一个解决方案,也就是我将要使用的方案:

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

第一种方法比第二种方法“慢99.92%”,所以第二种方法是我推荐使用的 当然方法。

好吧,继续找其他逃避工作的方法。

screenshot of the benchmark

假设您想将数字 x 截断到 n 位。

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

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

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

You can use toFixed(2) to convert your float to a string with 2 decimal points. Then you can wrap that in floatParse() to convert that string back to a float to make it usable for calculations or db storage.

const truncatedNumber = floatParse(num.toFixed(2))

I am not sure of the potential drawbacks of this answer like increased processing time but I tested edge cases from other comments like .29 which returns .29 (not .28 like other solutions). It also handles negative numbers.