gpt4 book ai didi

Solution for Javascript toFixed and math.round wrong issue(Java脚本修复和数学化错误问题的解决方案)

转载 作者:bug小助手 更新时间:2023-10-26 21:31:38 24 4
gpt4 key购买 nike



Is there a way to proper round the number 35.855 to have two decimals in javascript? Trying to round it has different solutions based on the environment (35.85 in Chrome, 35.86 in IE9).

有没有一种方法可以在JavaScript中正确地将35.855四舍五入到两位小数?根据环境的不同,有不同的解决方案(Chrome中为35.85,IE9中为35.86)。


I was looking for a solution at which javascript does wrong rounding for the decimals (rounding .5 values down instead up) and haven't found a solution that covered all the values that I had. They behaved other in different environments / browsers.

我正在寻找一种解决方案,在这个问题上,javascript对小数进行错误的舍入(将0.5值向下舍入,而不是向上舍入),但还没有找到覆盖我所有值的解决方案。它们在不同的环境/浏览器中表现不同。




console.log(Math.round(35.855*100)/100);
// result: 35.85 (IE9 : 35.86, Chrome: 35.85 ???)
console.log((35.855).toFixed(2));
// result: 35.85




更多回答

@Pointy But IE9 has expected behavior and Chrome has unexpected behavior.

@Pointty,但IE9有预期的行为,而Chrome有意外的行为。

Does this answer your question? Is floating point math broken?

这回答了你的问题吗?浮点数学有问题吗?

Never use floating point math for currencies. Use integer math and use the smallest coin value as base.

千万不要对货币使用浮点运算。使用整数数学,并使用最小的硬币价值作为基数。

If you're actually using floating point math for money, yes, I strongly recommend to redesign it. That's really horrible and could become very expensive. You could get sued, because even $0.1 + $0.2 returns a wrong value. Try 0.1 + 0.2 == 0.3

如果你真的在使用浮点数学来赚钱,是的,我强烈建议你重新设计它。这真的很可怕,而且可能会变得非常昂贵。你可能会被起诉,因为即使是0.1美元+0.2美元也会返回错误的值。尝试0.1+0.2==0.3

@SercanSametSavran every financial website I have worked on over the past 20+ years has used something like Java "BigDecimal" (fixed-point math), and systems like that have been the standard dating back to the 1960s with IBM mainframe BCD math hardware. You cannot, cannot use binary floating point for "money math". It's simply a rule of life.

@SercanSametSavran在过去20多年里,我工作过的每个金融网站都使用了类似Java“BigDecimal”(定点数学)的东西,这样的系统早在20世纪60年代就已经成为IBM大型机BCD数学硬件的标准。你不能,不能把二进制浮点用于“金钱数学”。这只是生活的一条规则。

优秀答案推荐

Make rounding of 1 character after the decimal part:

对小数部分后的1个字符进行舍入:




const round = (num, digits = 2) => {
const str = num.toString(), idx = str.indexOf('.');
if (idx < 0) return num;
const left = str[idx + 1 + digits]; // round this char
if (!left) return num;
return parseFloat(str.slice(0, idx + 1 + digits)) +
(left >= 5) * (str[0] === '-' ? -1 : 1) / 10 ** digits;
}
[35.855, 35.8549999, [-35.8549999, 3], 35.895, 35.8, 35].forEach(num =>
console.log(JSON.stringify(num), '->', round(...[].concat(num))));




And a benchmark:

和一个基准:


Cycles: 1000000 / Chrome/117
------------------------------------------------------------
Alexander slice       151/min  1.0x  163  166  159  151  169
Sercan Samet Savran   845/min  5.6x  846  845  846  851  859
------------------------------------------------------------
https://github.com/silentmantra/benchmark



<script benchmark data-count="1000000">

// @benchmark Alexander slice
const round = (num, digits = 2) => {
const str = num.toString();
const idx = str.indexOf('.');
if(idx < 0){
return num;
}
const left = str[idx + 1 + digits];
return left ? parseFloat(str.slice(0, idx + 1 + digits)) +(left >= 5) * (str[0] === '-' ? -1 : 1)/ 10 ** digits : num;
}
// @run

round(35.855);
round(35.8549999);
round(35.8549999, 3);
round(35.85);
round(35.8);
round(35);

// @benchmark Sercan Samet Savran

function roundToTwoDecimal(myNumber){
let myStrNumber = myNumber.toString();
// checking our number has decimals and if enough decimal points are present
if(myStrNumber.split(".").length > 1 && myStrNumber.split(".")[1].length > 2){
// doubling the last decimal e.g. 35.855 is now = 35.8555 and parsing back to float
myStrNumber += myStrNumber.substring(myStrNumber.length-1);
myNumber = parseFloat(myStrNumber);
} // no additional decimal needed here.
// returning the myNumber*100 = 3585.55 ---round--> 3586 / 100 = 35.86
return Math.round(myNumber*100)/100;
}

// @run

roundToTwoDecimal(35.855);
roundToTwoDecimal(35.8549999);
roundToTwoDecimal(35.8549999, 3);
roundToTwoDecimal(35.85);
roundToTwoDecimal(35.8);
roundToTwoDecimal(35);


</script>
<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>





My solution is just to add the same digit at the end of the number (if there are more than 1 digit), in order to force the previous number to round properly.

我的解决方案是在数字的末尾添加相同的数字(如果有超过1位数字),以强制前一个数字正确舍入。


function roundToTwoDecimal(myNumber){
let myStrNumber = myNumber.toString();
// checking our number has decimals and if enough decimal points are present
if(myStrNumber.split(".").length > 1 && myStrNumber.split(".")[1].length > 2){
// doubling the last decimal e.g. 35.855 is now = 35.8555 and parsing back to float
myStrNumber += myStrNumber.substring(myStrNumber.length-1);
myNumber = parseFloat(myStrNumber);
} // no additional decimal needed here.
// returning the myNumber*100 = 3585.55 ---round--> 3586 / 100 = 35.86
return Math.round(myNumber*100)/100;
}

更多回答

Nice one. Do you think, working with regex will be more performant in that case?

好样的。你认为在这种情况下,使用正则表达式会更好吗?

@SercanSametSavran i want to split manually and make a benchmark

@SercanSametSavran我想手动拆分并制定基准

Thank you. That would be great. Looking forward for the results.

谢谢。那太好了。期待着结果。

@SercanSametSavran finished, removed the regex version since it's twice slower

@SercanSametSavran已完成,删除了regex版本,因为它的速度慢了两倍

Sorry for late response. This works without any issues so far. Thank you.

很抱歉,回复晚了。到目前为止,这一功能运行正常,没有任何问题。谢谢。

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com