【发布时间】:2017-01-14 22:00:48
【问题描述】:
这两种 C# 方法是完全确定的吗?因为它们在所有平台上产生相同的结果?
Fix64 是 struct,具有 rawValue 类型为 long 的字段。
ONE 是这样定义的常量 const long ONE = 1L << 32;
功能一:
public static explicit operator Fix64(double value) {
return new Fix64((long)(value * ONE));
}
Fix64 接受long 值的构造函数只是将其分配给rawValue 字段。这里讨论的操作是乘法。 ONE 将转换为 double。然后两个double 值将相乘。根据 C# 规范,这可以以更高的精度发生。然后结果被long cast 截断。如果在不同平台上使用不同的精度进行乘法运算,得到的long 值的最低有效位是否有可能不同?还是这种方法是完全确定的?
功能2:
public static explicit operator double(Fix64 value) {
return (double)value.rawValue / ONE;
}
这类似于第一个示例。只是在这里我们在doubles 之间进行了除法运算,并且我们将结果作为double 返回。如果我们将此方法的结果与另一个double 进行比较,编译器是否有可能在比较期间以更高的精度保留结果double?
另一个演员表会确保这种比较始终是确定性的吗?
(double)((double)value.rawValue / ONE)
编辑:这两个函数在 FixedPoint64 类型和 double 类型之间转换。这里的论点是,通过只进行单一操作,我们没有使用扩展的中间浮点值来进行额外的操作。因此,通过立即将结果截断为标准精度,计算应该是确定性的。或者这个逻辑有什么缺陷?
【问题讨论】:
-
你肯定已经知道答案了。您犯的基本错误是假设它与您使用的表达式有关。这是不正确的,您不能假设 value 参数是一致的。
-
@HansPassant 我不明白你的意思。这两个功能的答案是否都是否定的?我需要将双精度值转换为 Fix64 结构并多次返回双精度值。我需要知道这些转换是否会在不同平台上产生相同的结果,或者是否需要修复它们。我已经阅读了一些论点,即确定性问题仅出现在多个操作的中间结果中,因为 FPU 扩展精度,并且可能出现在超越函数的实现中,但不会像第一个函数那样被立即截断的单个计算。
-
它会影响 所有 浮点运算。包括产生 value 参数的任何表达式。您发布的 sn-p 中的代码不会使其或多或少不一致。请记住基本指导,double 永远不能存储超过 15 个准确数字。对于在完全相同的操作系统风格上运行的完全相同的编译程序,计算是一致的。
-
如果您指的是传递给第一个函数的双值参数,则该值将从磁盘读取(应在所有平台上保持一致)或函数 2 的产品,存储在双场。该存储的双精度值不会被修改(仅比较)。对于所有的计算,都会先转换为定点Fix64结构,修改为定点数,然后再用函数2转换回double。问题是,这两个函数中的任何一个都需要固定吗?
标签: c# .net floating-point deterministic