我有Java中的算法/计算和单元测试。单元测试期望结果具有一定的精度/ delta。现在我将算法移植到.NET中,并希望使用相同的单元测试。我使用双数据类型。
问题是Java对Math类中的某些操作使用strictfp(64位)。 .NET使用FPU / CPU总是(80位)。 .NET更精确,更快捷。 Java更具可预测性。
因为我的算法是循环的并且重复使用前一轮的结果,所以误差/差异/更高精度累积太大。我不依赖速度(单元测试)。我很高兴在生产中使用.NET精度,但我想验证实现。
从JDK考虑这个
public final class Math {
public static double atan2(double y, double x) {
return StrictMath.atan2(y, x); // default impl. delegates to StrictMath
}
}
我正在寻找在.NET中使用严格FP的库或技术。
抢先评论:我确实理解IEEE 754格式以及浮点数不是精确的十进制数或分数这一事实。没有十进制,没有BigInt或BigNumber。请不要这样回答,谢谢。
答案 0 :(得分:4)
我在今年早些时候已经对这个问题进行了广泛的研究,因为我想知道是否有可能在.NET中的浮点运算上建立多人模拟。我的一些发现可能对您有用:
It is possible to emulate "strict" mode by inserting redundant casts everywhere,但这似乎是一个脆弱的,C#特定且乏味的解决方案。
32位JIT发出x87指令,但64位JIT发出SSE指令。在Microsoft和Mono的实现上都是如此。与x87不同,SSE floating arithmetic is reproducible。
我相信System.Math只是调用等效的C运行时函数,虽然我无法进入程序集来验证这一点(如果有人知道如何执行此操作,请检查!)。 C运行时尽可能使用SSE版本的超越函数,除了少数情况,特别是sqrt(但是通过instrinsics写一个包装器是微不足道的)。根据SSE的本质,这些必须是可重复的。 It is programatically possible to determine whether the C runtime is using its SSE implementation rather than x87
对于SSE中不可用的剩余超越函数(fmod,sinh,cosh,tanh),如果在x87上没有对其结果进行进一步操作,它们可能不会导致重现性问题。
简而言之,坚持使用64位CLR可以解决算术问题;对于超越函数,大多数已经在SSE中实现,如果你不对结果执行任何x87算术,我甚至不确定这是必要的。
答案 1 :(得分:2)
不幸的是,没有办法在C#中强制执行FP严格性。.Net CLR只是缺乏以最小的精度进行计算的能力。
我认为这会带来性能提升 - 它并不会检查您是否需要更低的精度。也没有必要 - .Net不能在虚拟机中运行,所以不用担心不同的浮点处理器。
但是strictfp
不是可选的吗?你可以在没有strictfp
修饰符的情况下执行Java代码吗?然后它应该采用与.Net
因此,不是强制.Net使用strictfp
而是检查它与Java代码的值相同,您可以强制Java不使用strictfp
并检查它是否相同作为.Net代码。