除法结果不正确(Incorrect division results)

编程入门 行业动态 更新时间:2024-10-28 09:19:40
除法结果不正确(Incorrect division results)

我有一个时间计算器,已经很好地工作了很多年。 但是,总是困扰我的一件事是,如果使用小数秒,结果将成为浮点“错误”的牺牲品。 所以,我最近改用了这个BigDecimal库 。

现在,我收到了数学错误。 这是我今天收到的错误报告的简化测试用例: 27436 / 30418返回1而不是预期的0.9019659412190151 。

为了说明我的问题,这里是Chrome中的Javascript控制台会话:

> first = 27436 27436 > second = 30418 30418 > first / second 0.9019659412190151 // expected result, but using JS numbers, not BigDecimals > firstB = new BigDecimal(first.toString()) o > secondB = new BigDecimal(second.toString()) o > firstB / secondB 0.9019659412190151 // this is a JS number, not a BigDecimal, so it's susceptible to the problems associated with floating-point. > firstB.divide(secondB) o // BigDecimal object > firstB.divide(secondB).toString() "1" // huh? Why 1? > firstB.divideInteger(secondB).toString() "0"

如您所见, divide()方法不会产生我期望的结果。 我需要做些什么不同的事情?

更新

以下是一些更多细节,以回应评论。

首先,有几个人建议使用BigDecimal是过度的。 这可能是,但我认为在做出决定之前需要更多细节。 这个应用程序是一个时间计算器 ,所以有一些东西促使我切换到BigDecimal。 首先,因为这是一个计算器,所以向用户显示正确答案很重要。 如果用户输入0.1 s + 0.2 s ,他们希望答案为0.3 s ,而不是Javascript将显示的答案( 0.30000000000000004 )。

我真的不想限制精度超出我在JS中使用的精度,这样我就可以使用整数,因为我不知道用户需要的最大精度。 我认为大多数人从不使用小数秒,但从我收到的电子邮件来看,有些人会这么做。 我目前在内部存储所有时间为秒。

有人建议我将数字存储为精确分数。 不幸的是,我不知道这意味着什么。 也许是因为我对数学知之甚少。 我不知道滚动自己的数学库; 这就是我使用BigDecimal的原因。 它已经存在了很长时间,所以我很犹豫地说我的问题是由于BigDecimal中的一个错误。 我怀疑这是我使用它的方式中的一个错误。

最后,我并没有特别强调BigDecimal。 我愿意接受其他建议,前提是我可以使用他缺乏数学技能的建议。

I've got a time calculator that has worked reasonably well for a number of years. One thing that always bothered me, though, was that if one used fractional seconds, the results would fall victim to floating-point "errors". So, I recently switched to using this BigDecimal library.

Now, I'm getting math errors. Here's a simplified test case from a bug report I received today: 27436 / 30418 is returning 1 instead of the expected 0.9019659412190151.

To illustrate my problem, here's a Javascript console session in Chrome:

> first = 27436 27436 > second = 30418 30418 > first / second 0.9019659412190151 // expected result, but using JS numbers, not BigDecimals > firstB = new BigDecimal(first.toString()) o > secondB = new BigDecimal(second.toString()) o > firstB / secondB 0.9019659412190151 // this is a JS number, not a BigDecimal, so it's susceptible to the problems associated with floating-point. > firstB.divide(secondB) o // BigDecimal object > firstB.divide(secondB).toString() "1" // huh? Why 1? > firstB.divideInteger(secondB).toString() "0"

As you can see, the divide() method isn't producing the result I expect. What do I need to do differently?

Update

Here are some more details, in response to the comments.

First, several people suggested that using BigDecimal was overkill. That might be, but I think that more details are necessary before making that decision. This app is a time calculator, so there are a couple of things that pushed me to switch to BigDecimal. First, because this is a calculator, it's important to show the user a correct answer. If the user enters 0.1 s + 0.2 s, they expect the answer to be 0.3 s, not the answer that Javascript will show them (0.30000000000000004).

I don't really want to limit the precision beyond what I can use in JS so that I can use integers, because I don't know the maximum precision my users need. Most never use fractional seconds, I think, but judging from the email I've received, some do. I'm currently storing all times internally as seconds.

Someone suggested that I store the numbers as exact fractions. Unfortunately, I don't know what that means. Perhaps it's because I don't know too much about math. I don't know enough to roll my own math library; that's why I'm using BigDecimal. It's been around for a long time, so I'm hesitant to say that my problem is due to a bug in BigDecimal. I suspect rather that it's a bug in the way I'm using it.

Finally, I'm not wedded to BigDecimal specifically. I'm open to other suggestions, provided that I can use them with my deficient math skills.

最满意答案

我还没有在任何生产代码中使用过BigDecimal,但发现这个问题很有趣,所以我试试看。 你是否需要MathContext作为除法函数的参数。 根据你的例子,我就是这样做的:

console.log(firstB.divide(secondB, new MathContext(100)).toString());

创建一个上下文,告诉BigDecimal在科学模式输出中使用100位数:

0.9019659412190150568742192123085015451377473864159379314879347754618975606548754027220724570977710566

还有控制不同输出模式PLAIN , SCIENTIFIC和ENGINEERING +各种舍入模式的选项。

关于jsfiddle的完整示例

更新:默认输出格式为SCIENTIFIC ,而不是PLAIN 。 这里的例子

更新2: 在这里创建了一个微小的性能测试,看起来BigDecimal比原生javascript分区慢大约10000倍。

I haven't used BigDecimal in any production code yet but found this question interesting so I though I give it a try. You are right about the need for a MathContext as parameter to the division function. Here is what I did, based on your example:

console.log(firstB.divide(secondB, new MathContext(100)).toString());

Creating a context that tells the BigDecimal to use 100 digits in scientific mode outputs:

0.9019659412190150568742192123085015451377473864159379314879347754618975606548754027220724570977710566

There's also options to control different output modes PLAIN, SCIENTIFIC and ENGINEERING + various rounding modes.

Full example on jsfiddle

Update: The default output format is SCIENTIFIC, not PLAIN. Examples here

Update 2: Created a tiny performance test here, looks like BigDecimal is about 10000 times slower than native javascript division.

更多推荐

本文发布于:2023-08-07 20:32:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1465797.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:除法   不正确   Incorrect   division   results

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!