这两种方法是确定的吗?
本文关键字:两种 方法 | 更新日期: 2023-09-27 18:06:05
这两个c#方法是完全确定的吗-因为它们在所有平台上产生相同的结果?
Fix64
为struct
, rawValue
字段类型为long
。ONE
是这样定义的常量const long ONE = 1L << 32;
函数1 :
public static explicit operator Fix64(double value) {
return new Fix64((long)(value * ONE));
}
Fix64
构造函数接受long
值,只是将其分配给rawValue
字段。这里的运算是乘法。ONE
将被转换为double
。然后两个double
值相乘。根据c#规范,这可以以更高的精度发生。然后用long
强制转换截断结果。如果在不同的平台上使用不同的乘法精度,那么所得到的long
值的最低有效位是否有可能不同?或者这种方法是完全确定的?
函数2 :
public static explicit operator double(Fix64 value) {
return (double)value.rawValue / ONE;
}
这与第一个示例类似。这里我们在double
之间进行除法运算,然后返回结果为double
。是否有可能,如果我们将此方法的结果与另一个double
进行比较,编译器可以在比较期间留下更高精度的double
?
另一个强制类型转换能确保这个比较总是确定性的吗?
(double)((double)value.rawValue / ONE)
编辑:这两个函数在FixedPoint64类型和double类型之间转换。这里的论点是,通过只执行单个操作,我们没有使用扩展的中间浮点值进行额外的操作。因此,通过立即截断结果到标准精度,计算应该是确定的。或者这种逻辑有什么缺陷吗?
答案是肯定的,两者都是确定性的。我从库的作者那里得到的解释是:
对于乘法/除法,如果其中一个FP数是两个数的幂(2^x),在计算过程中有效/尾数不会改变。只有指数会改变(点会移动)。所以舍入永远不会发生。结果将是确定的。
示例:像2^32这样的数字表示为(exponent: 32,尾数:1)。如果我们将它与另一个浮点数(exp, man)相乘,结果是(exp + 32, man * 1)。对于除法,结果是(expo - 32, man * 1)。尾数乘以1不会改变尾数,所以它有多少位无关。