是否可以在不诉诸任意精度数据类型的情况下删除浮点错误?

Con*_*ion 10 floating-point precision rounding

我想知道,在特定条件下,是否可以在不使用任意精度数据类型的情况下删除浮点错误.

问题是通常的问题.语言是Ruby,但它包含在任何语言中:

f = 1829.82
=> 1829.82

f / 12.0
=> 152.485

(f / 12.0).round(2)
=> 152.48
Run Code Online (Sandbox Code Playgroud)

为什么不是152.49?因为浮点的精度有限:

format("%18.14f", f)
=> "1829.81999999999994"

format("%18.14f", f / 12.0)
=> "152.48499999999999"
Run Code Online (Sandbox Code Playgroud)

所以四舍五入是正确的.现在的问题是:有没有办法让我想反正答案,给出的下列情况:有上(数)业务强劲限制使用浮动进行的,所需要的精确度是有限的到小数点后两位(最多8个位数总共)和少量剩余的"错误"圆形答案是可以接受的吗?

用户可以输入有效的Ruby字符串,例如:

"foo / 12.0"
Run Code Online (Sandbox Code Playgroud)

其中foo是在执行字符串的上下文中提供的数字,但其中'12 .0'是用户输入的内容.想象一下带有一些免费公式字段的电子表格.字符串简单地被评估为Ruby,因此12.0变为Float.我可以使用ruby_parser + ruby​​2ruby gems构建一个解析树,将数据类型转换为Bignum,Rational,来自Flt库的东西,十进制浮点表示或者你有什么,但这很棘手,因为实际的字符串可以变成有点复杂,所以我不想这样做.如果没有其他可能的话,我会这样做,但这个问题是专门在这里看看我是否可以避开这条道路.因此,12.0的数据类型是严格Float和结果严格Float和我能做的唯一的事情是解释片段的最终答案,并试图"纠正"它,如果它四舍五入"错误"的方式.

用户唯一的计算涉及精度为两位小数的数字(总共最多8位).使用'simple'我的意思是浮点错误没有机会累积:我可以添加其中两个数字并将一个除以整数,但随后计算完成,结果舍入并存储并随后进行计算基于该舍入数字.通常只有一个浮点错误都会涉及,但我认为问题并不显著改变,如果两者可以积累,但残留的错误率可能是通过定义较大.

首先想到的是首先舍入到3位小数,然后是2位.但是,这不起作用.这将导致

152.48499999999999 => 152.485 => 152.49
Run Code Online (Sandbox Code Playgroud)

但是也

152.4846 => 152.485 => 152.49
Run Code Online (Sandbox Code Playgroud)

这不是你想要的.

接下来我想到的是将最小可能的增量(如人们已经指出的,取决于所考虑的浮点值)添加到浮点数(如果它在.5边界上轻推它).我主要想知道这可能导致"误报"的频率:添加最小增量的数字,即使它刚好低于.5边界的事实不是由于浮点错误,但是因为这只是计算的结果?

第二个选择是:只要永远的最小增量增加的数字,因为.5地区是唯一一个在那里也无妨重要.

编辑:我刚刚重写了问题,将我的部分答案纳入评论中,正如cdiggins建议的那样.我将奖励给了Ira Baxter积极参与讨论,尽管我还不确定他是对的:Mark Ransom和Emilio M Bumachar似乎支持我的观点,即在实践中,可能会进行修正相对大多数情况下,会产生"正确"的结果.

我仍然需要进行实验,看看结果是多么频繁,我完全打算这样做,但是我可以花在这上面的时间有点受限,所以我还没有完成它.这个实验并非无足轻重.

Nem*_*emo 6

听起来你想要的是固定精度十进制数.实现这些的一个好的库比自己一起黑客攻击更可靠.

对于Ruby,请查看Flt库.

  • @Confusion:如果你要坚持你不能改变任何东西,我不知道你将如何得到修复. (2认同)

Emi*_*har 5

"有可能在不诉诸无限精度数据类型的情况下删除浮点错误."?

不会.浮点错误是计算机唯一涉及数字运算的错误.如果删除所有错误,根据定义,您的精度是无限的.

这听起来很迂腐,这不是我的意图.我想指出在你明显的技术问题下面存在一个很大的概念问题.除非您知道它们的正确值(即无限精度值或承载该信息的其他形式),否则您无法根据其正确值来正确舍入错误数字.

您添加少量数字的想法可能会在统计上得出结论,但仅限于统计数据.我建议你写一个脚本来测试大量的案例,随机数不超过两位小数.(脚本还需要以无限精度进行数学运算,以便知道正确的比较答案)这样,您就可以测量校正和误报.