在 java 中转换 80 位扩展精度
Convert 80-bit extended precision in java
我正在开发一个程序,可以将非常旧的 Open Access 4 .df 文件转换为
其他格式并创建数据库脚本 - 我已经能够转换每个
除十进制类型外的可能类型。我发现字节顺序必须是 80 位扩展精度。我已经尝试自己进行转换,但无法在 Java.[= 中完成从 80 位扩展精度 (https://en.wikipedia.org/wiki/Extended_precision#x86_Extended_Precision_Format) 到 String 和 String 到 80 位扩展精度的转换14=]
- 示例:
价值:1,235
来自 df 文件的十六进制:40 00 9e 06 52 14 1e f0 db f6
- 示例:
价值:0,750
来自 df 文件的十六进制:3f ff c0 00 00 00 00 00 00 00
也许有人可以帮助转换?
此致
@EJP 评论:
好吧,我扔掉了最后 16 位,所以我得到了 3f ff c0 00 00 00 00 00 关于 (Java - Convert hex to IEEE-754 64-bit float - double precision) 我尝试用
转换它
String hex = "3fffc00000000000";
long longBits = Long.valueOf(hex ,16).longValue();
double doubleValue = Double.longBitsToDouble(longBits);
但结果是 1,984375 而不是 0,750
我不确定它是否有资格作为答案或者是否有可能回答,因为...你确定它是标准的 80 位浮点点格式?因为照原样,它看起来有点奇怪。以你的第一个例子为例:
40 00 9e...
这里0x4000−16383=1是指数。尾数以高位1
开头,对应整数部分,所以应该是1,... x 2^1的形式,大于2。但是你说应该是1235。没有意义。
我在 Java 中创建了这个丑陋的 hack,它有点组装双:
long high = 0x40_00L;
long low = 0x9e_06_52_14_1e_f0_db_f6L;
long e = (((high & 0x7FFFL) - 16383) + 1023) & 0x7FFL;
long ld = ((high & 0x8000L) << 48)
| (e << 52)
| ((low >>> 11) & 0xF_FFFF_FFFF_FFFFL);
System.out.printf("%16X\n", ld);
double d = Double.longBitsToDouble(ld);
System.out.println(d);
假设输入是正确的 80 位值,这个片段应该可以正常工作,除了它没有正确舍入,没有检查溢出,没有处理非规范化的值并且可能无法处理像 NaN 这样的特殊值.对于这个输入,它打印
4003C0CA4283DE1B
2.46913578
不是 1,235!然后我使用了这个 C++ 代码(用 GCC 编译,其中 long double
是 80 位格式):
#include <stdio.h>
int main() {
long long high = 0x4000;
long long low = 0x9e0652141ef0dbf6;
long double d;
char *pd = (char*)&d, *ph = (char*)&high, *pl = (char*)&low;
for (int i = 0; i < 8; ++i) {
pd[i] = pl[i];
}
for (int i = 0; i < 2; ++i) {
pd[8 + i] = ph[i];
}
printf("%lf\n", (double) d);
}
它还打印 2.469136。
我正在开发一个程序,可以将非常旧的 Open Access 4 .df 文件转换为 其他格式并创建数据库脚本 - 我已经能够转换每个 除十进制类型外的可能类型。我发现字节顺序必须是 80 位扩展精度。我已经尝试自己进行转换,但无法在 Java.[= 中完成从 80 位扩展精度 (https://en.wikipedia.org/wiki/Extended_precision#x86_Extended_Precision_Format) 到 String 和 String 到 80 位扩展精度的转换14=]
- 示例:
价值:1,235
来自 df 文件的十六进制:40 00 9e 06 52 14 1e f0 db f6
- 示例:
价值:0,750
来自 df 文件的十六进制:3f ff c0 00 00 00 00 00 00 00
也许有人可以帮助转换?
此致
@EJP 评论: 好吧,我扔掉了最后 16 位,所以我得到了 3f ff c0 00 00 00 00 00 关于 (Java - Convert hex to IEEE-754 64-bit float - double precision) 我尝试用
转换它String hex = "3fffc00000000000";
long longBits = Long.valueOf(hex ,16).longValue();
double doubleValue = Double.longBitsToDouble(longBits);
但结果是 1,984375 而不是 0,750
我不确定它是否有资格作为答案或者是否有可能回答,因为...你确定它是标准的 80 位浮点点格式?因为照原样,它看起来有点奇怪。以你的第一个例子为例:
40 00 9e...
这里0x4000−16383=1是指数。尾数以高位1
开头,对应整数部分,所以应该是1,... x 2^1的形式,大于2。但是你说应该是1235。没有意义。
我在 Java 中创建了这个丑陋的 hack,它有点组装双:
long high = 0x40_00L;
long low = 0x9e_06_52_14_1e_f0_db_f6L;
long e = (((high & 0x7FFFL) - 16383) + 1023) & 0x7FFL;
long ld = ((high & 0x8000L) << 48)
| (e << 52)
| ((low >>> 11) & 0xF_FFFF_FFFF_FFFFL);
System.out.printf("%16X\n", ld);
double d = Double.longBitsToDouble(ld);
System.out.println(d);
假设输入是正确的 80 位值,这个片段应该可以正常工作,除了它没有正确舍入,没有检查溢出,没有处理非规范化的值并且可能无法处理像 NaN 这样的特殊值.对于这个输入,它打印
4003C0CA4283DE1B
2.46913578
不是 1,235!然后我使用了这个 C++ 代码(用 GCC 编译,其中 long double
是 80 位格式):
#include <stdio.h>
int main() {
long long high = 0x4000;
long long low = 0x9e0652141ef0dbf6;
long double d;
char *pd = (char*)&d, *ph = (char*)&high, *pl = (char*)&low;
for (int i = 0; i < 8; ++i) {
pd[i] = pl[i];
}
for (int i = 0; i < 2; ++i) {
pd[8 + i] = ph[i];
}
printf("%lf\n", (double) d);
}
它还打印 2.469136。