Ruby 存储/检索浮点数的断言

Ruby 存储/检索浮点数的断言,ruby,ruby-on-rails-3,unit-testing,testing,Ruby,Ruby On Rails 3,Unit Testing,Testing,(这个问题是在Ruby上下文中提出的,但如果用更一般的方式回答,我不会感到不安。) 所以(几乎)每个人都知道,比较数学计算中涉及的浮点数是否相等是不可能的,并且您必须测试范围(在Ruby中,就像这样): 然而,当一个浮点数从一个子系统传递到另一个子系统(比如在Ruby上下文中)时,是否仍有必要检查浮点数是否相等 我个人认为,在这里,在_delta中断言_仍然是一个好主意,因为我不知道,也许很多人也不知道,概念上的浮点值0.5的传递方式是否能够与浮点值0.5的等号进行比较。是真的如此,还是我对浮点

(这个问题是在Ruby上下文中提出的,但如果用更一般的方式回答,我不会感到不安。)

所以(几乎)每个人都知道,比较数学计算中涉及的浮点数是否相等是不可能的,并且您必须测试范围(在Ruby中,就像这样):

然而,当一个浮点数从一个子系统传递到另一个子系统(比如在Ruby上下文中)时,是否仍有必要检查浮点数是否相等


我个人认为,在这里,在_delta中断言_仍然是一个好主意,因为我不知道,也许很多人也不知道,概念上的浮点值0.5的传递方式是否能够与浮点值0.5的等号进行比较。是真的如此,还是我对浮点数的存储和传递过于偏执?答案在多大程度上取决于所使用的语言?

这在很大程度上取决于子系统如何处理浮点。在Ruby中(至少是1.8和1.9),float简单地包装了一个双精度数字(C中的字面意思是a
double
,在大多数现代体系结构中存储为a)。当您在该表示中传递或复制数字时,位不会改变

但是,当您将浮点传递到子系统时,它可能会更改底层表示。在您给出的示例中,您使用JSON序列化数字,这涉及到将浮点值转换为字符串,然后再转换回字符串。无法保证恢复的精度超过15-16位(假设您以该精度进行转换)。这似乎很多,但不足以确保所有可能的浮点值严格相等。

顺便说一句,
5.0==(3.5+1.5)
返回
true
。像
Math::acos(1.0/Math::sqrt(2))==Math::PI/4
这样的情况返回false,因为存在关于
1e-16
的差异。涉及非常大和非常小的数字的总和也有问题:
2.0e19+5.0-2.0e19
的结果是0.0,而不是5.0(双精度没有足够的精度位,因此5.0被舍入)。
assert_in_delta 5.0, 3.5+1.5, 0.0001
json={:foo => 0.5}.to_json
# POST the JSON to a Rails controller, that puts it in a Mongo database
found_obj=pull_obj_out_of_Mongo # details not important here
assert_in_delta 0.5, found_obj[:foo], 0.0001