提问人:Merc 提问时间:3/11/2019 更新时间:3/14/2019 访问量:1987
向上或向下舍入时为 0.5
Rounding up or down when 0.5
问:
我在达到 0.5 时对 Javascript 进行四舍五入的方式有问题。 我正在编写征税计算器,并注意到结果中有 0.1c 的差异。
问题是,他们的结果是我的应用程序转化为 ,而关税说.21480.705
21480.71
21480.70
这是我在 Javascript 中看到的:
(21480.105).toFixed(2)
"21480.10"
(21480.205).toFixed(2)
"21480.21"
(21480.305).toFixed(2)
"21480.31"
(21480.405).toFixed(2)
"21480.40"
(21480.505).toFixed(2)
"21480.51"
(21480.605).toFixed(2)
"21480.60"
(21480.705).toFixed(2)
"21480.71"
(21480.805).toFixed(2)
"21480.81"
(21480.905).toFixed(2)
"21480.90"
问题:
- 这种不稳定的路由到底是怎么回事?
- 获得“四舍五入”结果的最快、最简单的方法是什么(当达到 0.5 时)?
答:
您可以四舍五入为整数,然后在显示以下内容时以逗号移动:
function round(n, digits = 2) {
// rounding to an integer is accurate in more cases, shift left by "digits" to get the number of digits behind the comma
const str = "" + Math.round(n * 10 ** digits);
return str
.padStart(digits + 1, "0") // ensure there are enough digits, 0 -> 000 -> 0.00
.slice(0, -digits) + "." + str.slice(-digits); // add a comma at "digits" counted from the end
}
这在大多数情况下都有效。(请参阅下面的注释。
舍入问题可以通过使用 指数表示法:
function round(value, decimals) {
return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}
console.log(round(21480.105, 2).toFixed(2));
在 http://www.jacklmoore.com/notes/rounding-in-javascript/ 找到
注意:正如 Mark Dickinson 所指出的,这不是一个通用的解决方案,因为它在某些情况下会返回 NaN,例如 和 具有较大的输入。
欢迎进行编辑以使其更加健壮。round(0.0000001, 2)
评论
21480.705
21480.70
21480.71
value = 0.000001
0.00
round
toFixed
round(0.123456, 5).toFixed(5)
if(val%1==0.705){ return roundDownForNoGoodReason(val); }
0.0000001 + 'e' + 2
"1e-7e2"
NaN
Math.round(0.0000001 + 'e' + 2)
原因 -
您可能听说过,在某些语言(例如 JavaScript)中,带有小数部分的数字调用浮点数,而浮点数则用于处理数值运算的近似值。不是精确的计算,近似值。因为您期望如何计算和存储 1/3 或 2 的平方根,并进行精确的计算?
如果你没有,那么现在你已经听说过了。
这意味着,当您键入数字文字 21480.105 时,最终存储在计算机内存中的实际值实际上不是 21480.105,而是它的近似值。最接近 21480.105 的值,可以表示为浮点数。
由于这个值不完全是 21480.105,这意味着它要么略高于该值,要么略低于该值。正如预期的那样,更多的将被四舍五入,更少的将被四舍五入。
解决方案 -
你的问题来自近似值,似乎你负担不起。解决方案是使用精确的数字,而不是近似值。
使用整数。这些都是准确的。将数字转换为字符串时添加小数点。
这种不稳定的路由到底是怎么回事?
请参考警告性的 Mozilla 文档,其中确定了这些差异的原因。“浮点数不能以二进制精确表示所有小数,这可能会导致意想不到的结果......”
另外,请参考浮点数学坏了吗? (感谢 Robby Cornelissen 提供参考)
获得“四舍五入”结果的最快、最简单的方法是什么(当达到 0.5 时)?
使用像会计 .js 这样的 JS 库来舍入、格式化和呈现货币。
例如。。。
function roundToNearestCent(rawValue) {
return accounting.toFixed(rawValue, 2);
}
const roundedValue = roundToNearestCent(21480.105);
console.log(roundedValue);
<script src="https://combinatronics.com/openexchangerates/accounting.js/master/accounting.js"></script>
另外,请考虑查看 JavaScript 中的 BigDecimal。
希望对您有所帮助!
评论
(Math.round(21480.105*100)/100).toPrecision(18)
由于四舍五入而产生。这并不意味着这适用于此类型的所有计算。"21480.1100000000006"
Math.round(1.005*100)/100
1
(Math.round(1.005*100)/100).toFixed(2)
1.00
因此,正如其他一些人已经解释的那样,“不稳定”舍入的原因是浮点精度问题。您可以使用 JavaScript 数字的方法对此进行调查。toExponential()
(21480.905).toExponential(20)
#>"2.14809049999999988358e+4"
(21480.805).toExponential(20)
#>"2.14808050000000002910e+4"
正如你在这里看到的,得到一个略小于 的双精度表示,而得到一个略大于原始值的双精度表示。由于该方法适用于双重表示形式,并且不知道您的原始预期值,因此它会尽其所能并且应该使用它所拥有的信息来执行所有操作。21480.905
21480.905
21480.805
toFixed()
解决此问题的一种方法是将小数点移动到乘法所需的小数位数,然后使用标准,然后再次将小数点移回,通过除法或乘以倒数。最后,我们调用方法以确保输出值正确填充零。Math.round()
toFixed()
var x1 = 21480.905;
var x2 = -21480.705;
function round_up(x,nd)
{
var rup=Math.pow(10,nd);
var rdwn=Math.pow(10,-nd); // Or you can just use 1/rup
return (Math.round(x*rup)*rdwn).toFixed(nd)
}
function round_down(x,nd)
{
var rup=Math.pow(10,nd);
var rdwn=Math.pow(10,-nd);
return (Math.round(x*-rup)*-rdwn).toFixed(nd)
}
function round_tozero(x,nd)
{
return x>0?round_down(x,nd):round_up(x,nd)
}
console.log(x1,'up',round_up(x1,2));
console.log(x1,'down',round_down(x1,2));
console.log(x1,'to0',round_tozero(x1,2));
console.log(x2,'up',round_up(x2,2));
console.log(x2,'down',round_down(x2,2));
console.log(x2,'to0',round_tozero(x2,2));
最后: 遇到这样的问题通常是坐下来好好想想你是否真的对你的问题使用了正确的数据类型。由于浮点错误会随着迭代计算而累积,而且由于人们有时对货币神奇地消失/出现在 CPU 中非常敏感,也许您最好将货币计数器保持在整数“美分”(或其他一些经过深思熟虑的结构)而不是浮点“美元”。
评论
21480.705
21480.70
21480.71
上一个:关闭非常繁忙的生产节点
下一个:如何确保变量是对象
评论
console.log(21480.105)