我正在根据我正在阅读的论文编写一个用于多精度算术的库。能够保证我使用的浮点数的属性非常重要。特别是,他们遵守IEEE 754标准的双精度浮点数。显然,我无法保证我的代码在意外平台上的行为,但对于我所写的x86和x64芯片组,我担心特别危险。显然,部分或全部x86 / x64芯片组可以在FPU寄存器中使用扩展精度浮点数,精度为80位。我不能容忍我在扩展精度FPU中处理算术而不是在每次操作后舍入到双精度,因为我使用的算法的正确性证明依赖于舍入。我可以很容易地识别扩展精度可能破坏这些算法的情况。
我在C#中编写代码。我怎样才能保证某些值是四舍五入的?在C中,我将变量声明为volatile,强制将它们写回RAM。这很慢,我宁愿将寄存器中的数字保持为64位浮点数,但这些算法的正确性是整点,而不是速度。无论如何,我需要一个C#的解决方案。如果这看起来不可行,我将用另一种语言解决问题。
答案 0 :(得分:2)
C#规范就此主题发表了这样的话:
只有在性能成本过高的情况下才能使这种硬件架构以较低的精度执行浮点运算,而不是要求实现失去性能和精度,C#允许更高精度的类型用于所有浮动点操作。除了提供更精确的结果外,这几乎没有任何可衡量的影响。
因此,需要第三方库来模拟符合IEEE 754标准的FPU的行为。其中一个是SoftFloat,它创建了一个类型SoftFloat
,它使用运算符重载来模拟标准double
行为。
答案 1 :(得分:1)
80位中间值的一个明显问题是,编译器和优化器很可能决定何时将值截断回64位。因此,不同的编译器可能最终为相同的浮点运算序列产生不同的结果。一个例子是像 b c d这样的操作。根据80位浮点寄存器的可用性,编译器可能会将 b舍入为64位,并将c * d保持为80位。我想这是你需要消除这种不确定性的问题的根源。
我认为您的选项在托管代码中非常有限。您可以像建议的其他答案一样使用第三方软件模拟。或者也许你可以尝试强迫双人进行长时间和后退。我无法检查这是否真的有效,但你可以在操作之间尝试这样的事情:
public static double Truncate64(double val)
{
unsafe
{
long l = *((long*) &val);
return *((double*) &l);
}
}
这也是类型检查:
public static double Truncate64(double val)
{
unsafe
{
return *((long*) &val);
}
}
希望有所帮助。