C++中的Float epsilon与C#不同。

3
所以我有一个小问题,出于性能原因,我一直在研究将我的C#代码的一部分转移到C++中。现在当我查看C#中的float.Epsilon时,它的值与我的C++值不同。
在C#中,该值的描述 by microsoft 是1.401298E-45。
在C++中,该值的描述 by cppreferences 是1.19209e-07;
为什么浮点数/单精度浮点数的最小可能值在这些语言之间会有所不同呢?
如果我没错的话,二进制值应该在字节数和甚至二进制值方面相等。或者我看待这个问题的方式有误吗?
希望有人可以帮助我,谢谢!

1
Epsilon的定义是不同的。在C#中,它是0和下一个值之间的差异,在C++中,它是1和下一个值之间的差异。 - gerum
那个微软页面充斥着关于浮点数的错误陈述。避免使用其中的信息。一些问题:(a)“零和 Epsilon 值的一半被认为是相等的”:你不能在 Float 中有 Epsilon 值的一半;它是不可表示的。(b)“格式由符号、23 位尾数或有效数字组成…”:有效数字是 24 位,虽然存储为 23 位在一个字段中,并且还有 1 位取决于指数字段。 - Eric Postpischil
“机器epsilon,代表由于舍入而产生的相对误差的上限…”:它可以作为单个操作中误差的度量标准,但不能说它代表上限或是相对误差。使用四舍五入法,实际上限是1/2个ULP,真正的相对误差有些复杂,因为它在一个二进制指数区间内变化。 - Eric Postpischil
“右侧的常数只精确到指定的位数”:两个值具有相同的精度;右侧的值对于1/3来说是不准确的。微软关于精度的声明很糟糕。 - Eric Postpischil
如果您创建了一个自定义算法来确定两个浮点数是否可以被视为相等,则必须使用大于Epsilon常量的值来建立可接受的绝对差距范围,以便将两个值视为相等。每个应用程序都必须处理虚假的正面和虚假的负面结果,这可能是特定于其情况的,并没有通用的解决方案来比较浮点数,因此“你必须使用大于 Epsilon 常量的值”并不正确。 - Eric Postpischil
在ARM系统上,Epsilon常量的值太小而无法被检测到,因此它等同于零。我怀疑他们是想说denormal数的flush-to-zero行为会干扰使用Epsilon常量。 - Eric Postpischil
3个回答

4
你引用的第二个值是IEEE binary32 值的 机器精度
你引用的第一个值不是机器精度。根据你链接的文档:

Epsilon 属性的值不等同于机器精度,机器精度表示由于浮点运算中舍入而产生的相对误差的上限。

机器精度的变体定义部分得知:

IEEE 标准未定义机器精度和单位舍入误差,因此使用不同的定义可能会造成一些混乱。

...

下面这个不同的定义在学术界之外更为广泛:机器精度被定义为1与下一个较大的浮点数之间的差。

C# 文档使用了这个变体定义。
所以结论是你正在比较两种不同类型的 Epsilon。

3
请注意,您可以在C++中使用std::numeric_limits<float>::denorm_min()来获得与C#中的float.Epsilon相同的结果。 - IlCapitano

2

0
从您提供的链接中,如果您想要类似于.NET Single.Epsilon(“大于零的最小正单精度值”)的东西,您应该使用FLT_TRUE_MIN(“浮点数的最小正值”)的值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接