Java 中的 x86 80 位浮点类型
x86 80-bit floating point type in Java
我想模拟 x86 扩展精度类型并执行算术运算并转换为 Java 中的其他类型。
我可以尝试使用 BigDecimal 来实现它,但是涵盖所有围绕 NaN、无穷大和强制转换的特殊情况可能是一项乏味的任务。我知道一些库提供比 double 精度更高的其他浮点类型,但我希望具有与 x86 80 位浮点相同的精度。
有Java库提供这样的浮点类型吗?如果没有,您能否提供其他提示,以比提出自定义 BigDecimal 解决方案更轻松地实现此类数据类型?
如果您知道您的 Java 代码实际上会 运行 在 x86 处理器上,请在汇编(或 C,如果 C 编译器支持的话)中实现 80 位算法并调用JNI.
如果您的目标是特定的非 x86 平台,请查看 qemu 代码。应该有一些方法可以只删除执行 80 位浮点运算的部分。 (编辑:qemu 的实现是 SoftFloat。)。用 JNI 调用它。
如果你真的想要跨平台的纯Java 80 位算法,你可能仍然可以将它与开源 CPU 模拟器中的 C 实现进行比较,以确保你解决正确的极端情况。
这与 java strictfp 选项有点相反,即 将计算限制 为 8 字节,而它执行 80 位。
所以我的答案是 运行 64 位机器上的 JVM,也许在某些 hypervisor/OS VM 中,所以你有一个开发平台。
80 位值最好由 long
(尾数)和 int
(指数和符号)组合而成。对于许多操作,将 long 的上半部分和下半部分放入单独的 "long" 值中可能是最实用的,因此将两个具有匹配符号和指数的数字相加的代码可能类似于:
long resultLo = (num1.mant & 0xFFFFFFFFL)+(num2.mant & 0xFFFFFFFFL);
long resultHi = (num1.mant >>> 32)+(num2.mant >>> 32)+(resultLo >>> 32);
result.exp = num1.exp; // Should match num2.exp
if (resultHi > 0xFFFFFFFFL) {
exponent++;
resultHi = (resultHi + ((resultHi & 2)>>>1)) >>> 1; // Round the result
}
rest.mant = (resultHi << 32) + resultLo;
周围有点麻烦,但并非完全不可行。关键是
将数字分解成足够小的部分,以便您可以像这样进行所有数学运算
输入 "long".
顺便说一句,请注意,如果其中一个数字最初没有相同的指数,
有必要跟踪是否有任何位 "fell off the end"
将它向左或向右移动以匹配第一个数字的指数,以便
之后能够正确地舍入结果。
我想模拟 x86 扩展精度类型并执行算术运算并转换为 Java 中的其他类型。
我可以尝试使用 BigDecimal 来实现它,但是涵盖所有围绕 NaN、无穷大和强制转换的特殊情况可能是一项乏味的任务。我知道一些库提供比 double 精度更高的其他浮点类型,但我希望具有与 x86 80 位浮点相同的精度。
有Java库提供这样的浮点类型吗?如果没有,您能否提供其他提示,以比提出自定义 BigDecimal 解决方案更轻松地实现此类数据类型?
如果您知道您的 Java 代码实际上会 运行 在 x86 处理器上,请在汇编(或 C,如果 C 编译器支持的话)中实现 80 位算法并调用JNI.
如果您的目标是特定的非 x86 平台,请查看 qemu 代码。应该有一些方法可以只删除执行 80 位浮点运算的部分。 (编辑:qemu 的实现是 SoftFloat。)。用 JNI 调用它。
如果你真的想要跨平台的纯Java 80 位算法,你可能仍然可以将它与开源 CPU 模拟器中的 C 实现进行比较,以确保你解决正确的极端情况。
这与 java strictfp 选项有点相反,即 将计算限制 为 8 字节,而它执行 80 位。
所以我的答案是 运行 64 位机器上的 JVM,也许在某些 hypervisor/OS VM 中,所以你有一个开发平台。
80 位值最好由 long
(尾数)和 int
(指数和符号)组合而成。对于许多操作,将 long 的上半部分和下半部分放入单独的 "long" 值中可能是最实用的,因此将两个具有匹配符号和指数的数字相加的代码可能类似于:
long resultLo = (num1.mant & 0xFFFFFFFFL)+(num2.mant & 0xFFFFFFFFL);
long resultHi = (num1.mant >>> 32)+(num2.mant >>> 32)+(resultLo >>> 32);
result.exp = num1.exp; // Should match num2.exp
if (resultHi > 0xFFFFFFFFL) {
exponent++;
resultHi = (resultHi + ((resultHi & 2)>>>1)) >>> 1; // Round the result
}
rest.mant = (resultHi << 32) + resultLo;
周围有点麻烦,但并非完全不可行。关键是 将数字分解成足够小的部分,以便您可以像这样进行所有数学运算 输入 "long".
顺便说一句,请注意,如果其中一个数字最初没有相同的指数, 有必要跟踪是否有任何位 "fell off the end" 将它向左或向右移动以匹配第一个数字的指数,以便 之后能够正确地舍入结果。