提问人:kcssm 提问时间:2/6/2011 最后编辑:Rudi Visserkcssm 更新时间:12/7/2022 访问量:201686
在 javascript 中截断(不四舍五入)十进制数
Truncate (not round off) decimal numbers in javascript
问:
我正在尝试将十进制数截断到小数位。像这样的东西:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
做了几乎正确的事情,但它使价值四舍五入。我不需要四舍五入的值。希望在javascript中这是可能的。
答:
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46
评论
truncate(-3.14)
-4
var a = 65.1
var truncated = Math.floor(a * 100) / 100; // = 65.09
因此,这不是一个正确的解决方案
您可以通过减去 toFixed 的 0.5 来修复舍入,例如
(f - 0.005).toFixed(2)
评论
更新:
所以,毕竟事实证明,无论你多么努力地补偿它们,四舍五入的错误总是会困扰你。因此,应该通过精确地用十进制表示法来解决这个问题。
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);
}
评论
1.11.toFixedDown(1) + 22
1.122
23.1
0.toFixedDown(1)
0
-0.1
(-10.2131).toFixedDown(2) // ==> 10.21
(1e-7).toFixedDown(0) // ==> 1e-7
1e-(>=7)
1e-8
1e-9
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
如果这不是所需的行为,请在第一行插入对 的调用:Math.abs
var multiplier = Math.pow(10, Math.abs(digits)),
编辑:shendz 正确地指出,使用此解决方案将错误地产生 .有关发生这种情况的原因的更多信息,请阅读每个计算机科学家都应该了解的浮点运算知识。不幸的是,编写一个消除所有浮点错误来源的解决方案对于 javascript 来说非常棘手。在另一种语言中,你会使用整数或十进制类型,但使用 javascript......a = 17.56
17.55
此解决方案应该是 100% 准确的,但速度也会更慢:
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 数学库的好博客文章
评论
if(isNAN(result) result = 0;
以下是我对这个问题的看法:
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)
考虑利用双波浪号:~~
。
接受这个数字。乘以小数点后的实际数字,以便可以使用 截断到零位。将乘数除以外。利润。~~
function truncator(numToTruncate, intDecimalPlaces) {
var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better
return ~~(numToTruncate * numPower)/numPower;
}
我试图抵制用 parens 包装电话;我相信,操作顺序应该使它正常工作。~~
alert(truncator(5.1231231, 1)); // is 5.1
alert(truncator(-5.73, 1)); // is -5.7
alert(truncator(-5.73, 0)); // is -5
编辑:回想起来,我无意中也处理了小数点左边四舍五入的情况。
alert(truncator(4343.123, -2)); // gives 4300.
寻找这种用法的逻辑有点古怪,并且可能会从快速重构中受益。但它仍然有效。好运总比好。
评论
Math
100012345678
2147483647
只是为了指出一个对我有用的简单解决方案
将其转换为字符串,然后对其进行正则表达式...
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;
};
评论
or
~~
标记为解决方案的那个是我直到今天才找到的更好的解决方案,但 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 位小数或两位小数,或者永远如此,所以,你必须完成右边的前导零怎么办
// 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
这是 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/
评论
x = 0.0000
测试失败。返回。不如预期truncateDecimals (x, 2)
0
0.00
生成的类型仍然是一个数字...
/* 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,我肯定会这样称呼它 不良。– @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
评论
@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
小提琴:JS 数字向下舍入
PS:没有足够的 repo 来评论该解决方案。
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 有一些 Math 实用程序方法,可以将数字四舍五入、下限和降入到给定的十进制精度。这将留下尾随零。
他们采用一种有趣的方法,使用数字的指数。显然,这避免了舍入问题。
(注意:在下面的代码中是或或)func
Math.round
ceil
floor
// 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));
我用一种较短的方法写了一个答案。这是我想出的
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
适用于:
- 负数
- 非常小的数字(Number.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%”,因此第二种方法绝对是我推荐使用的方法。
好吧,回到寻找其他方法来避免工作......
假设您要截断数字 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
评论
trunc(1304.35,2) // 1304.34
num * pow
1304.35 * 100 // 130434.99999999999
你可以使用 toFixed(2) 将你的浮点数转换为小数点后 2 位的字符串。然后,您可以将其包装在 floatParse() 中,将该字符串转换回浮点数,使其可用于计算或数据库存储。
const truncatedNumber = floatParse(num.toFixed(2))
我不确定这个答案的潜在缺点,例如增加处理时间,但我测试了其他评论中的边缘情况,例如 .29,它返回 .29(而不是像其他解决方案那样的 .28)。它还处理负数。
评论