【问题标题】:Are these two methods deterministic?这两种方法是确定性的吗?
【发布时间】: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


【解决方案1】:

答案是肯定的,两者都是确定性的。我从图书馆的作者那里得到的解释是:

对于乘法/除法,如果 FP 数之一是两个数的幂 (2^x),则在计算过程中有效/尾数不会改变。只有指数会改变(点会移动)。所以舍入永远不会发生。结果将是确定性的。

示例:像 2^32 这样的数字表示为(指数:32,尾数:1)。如果我们将它与另一个浮点数 (exp, man) 相乘,结果是 (exp + 32, man * 1)。对于除法,结果是 (expo - 32, man * 1)。尾数乘以 1 不会改变尾数,所以它有多少位并不重要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-14
    • 2010-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-03
    相关资源
    最近更新 更多