NetBSD 长双麻烦
NetBSD long double trouble
我有简单的代码:
#include <stdio.h>
int main()
{
//char d[10] = {0x13, 0x43, 0x9b, 0x64, 0x28, 0xf8, 0xff, 0x7f, 0x00, 0x00};
//long double rd = *(long double*)&d;
long double rd = 3.3621e-4932L;
printf("%Le\n", rd);
return 0;
}
在我的 Ubuntu x64 上,它按预期打印 3.362100e-4932。在我的 NetBSD 上它打印 1.681050e-4932
为什么会发生,我该如何解决?我尝试了 clang 和 gcc,结果相同。
我的系统(VirtualBox 5.0 中的虚拟机):
uname -a
NetBSD netbsd.home 7.0 NetBSD 7.0 (GENERIC.201509250726Z) amd64
gcc --version
gcc (nb2 20150115) 4.8.4
clang --version
clang version 3.6.2 (tags/RELEASE_362/final)
Target: x86_64--netbsd
Thread model: posix
仅供参考
/usr/include/x86/float.h
定义为 LDBL_MIN
为 3.3621031431120935063E-4932L
并且此值大于 printf 结果。
/usr/include/x86/float.h
defines as LDBL_MIN
as 3.3621031431120935063E-4932L
And this value is greater than printf result.
LDBL_MIN
是类型 long double
的最小正 标准化 值。该类型可以表示较小的数字,它们只是次正规的。
我只能推测 NetBSD 问题的性质,但主要有两种可能性:
编译器将您的初始化常量转换为次正规数,该数与请求值相距甚远(相对而言)。
这个数字翻译得很好(但结果仍然是次正规的),而 NetBSD 的 printf()
对于次正规的数字是有问题的,或者至少对于这个数字是这样。
打印的数字是您预期的一半这一事实表明 long double
表示中的(二进制)指数存在问题。鉴于次正规数的 IEEE 格式的详细信息,很容易想象 printf()
不预期次正规数的实现会如何误解(二进制)指数字段以表示比实际表示的指数小一的指数,因此打印一个值是预期值的一半。这是我对正在发生的事情的猜测。
您可能还可以通过打印来区分错误的值和错误的显示情况,例如 rd * 4
。无论哪种方式,这都应该在正常数字的范围内,所以人们会假设 printf()
特定于次正规数字的错误不会影响它的打印。
至于如何进行,您有多种选择。我最有可能想到的是:
避免次正规数。这可能不切实际,但至少你可以使用 LDBL_MIN
作为你的初始化器,而不是一个最接近次正规 long double
.
的常量
忽略这个问题。如果您可以确认这是一个显示问题,而不是错误值问题,那么您可能不需要做任何事情来充分服务于更大的 objective.
修复 NetBSD 的 C 库。假设问题出在 printf()
中,修复可能不会很大,并且库是开源的,就像系统的其余部分一样。
提交错误报告并等待其他人修复它。如果您需要及时修复,那么这可能不适合,但如果您有时间等待,那么这对您来说几乎不需要付出任何努力。
已报告给 NetBSD
incorrect printf result for subnormal long double values
并在 NetBSD-current
中修复
我有简单的代码:
#include <stdio.h>
int main()
{
//char d[10] = {0x13, 0x43, 0x9b, 0x64, 0x28, 0xf8, 0xff, 0x7f, 0x00, 0x00};
//long double rd = *(long double*)&d;
long double rd = 3.3621e-4932L;
printf("%Le\n", rd);
return 0;
}
在我的 Ubuntu x64 上,它按预期打印 3.362100e-4932。在我的 NetBSD 上它打印 1.681050e-4932
为什么会发生,我该如何解决?我尝试了 clang 和 gcc,结果相同。
我的系统(VirtualBox 5.0 中的虚拟机):
uname -a
NetBSD netbsd.home 7.0 NetBSD 7.0 (GENERIC.201509250726Z) amd64
gcc --version
gcc (nb2 20150115) 4.8.4
clang --version
clang version 3.6.2 (tags/RELEASE_362/final)
Target: x86_64--netbsd
Thread model: posix
仅供参考
/usr/include/x86/float.h
定义为 LDBL_MIN
为 3.3621031431120935063E-4932L
并且此值大于 printf 结果。
/usr/include/x86/float.h
defines asLDBL_MIN
as3.3621031431120935063E-4932L
And this value is greater than printf result.
LDBL_MIN
是类型 long double
的最小正 标准化 值。该类型可以表示较小的数字,它们只是次正规的。
我只能推测 NetBSD 问题的性质,但主要有两种可能性:
编译器将您的初始化常量转换为次正规数,该数与请求值相距甚远(相对而言)。
这个数字翻译得很好(但结果仍然是次正规的),而 NetBSD 的
printf()
对于次正规的数字是有问题的,或者至少对于这个数字是这样。
打印的数字是您预期的一半这一事实表明 long double
表示中的(二进制)指数存在问题。鉴于次正规数的 IEEE 格式的详细信息,很容易想象 printf()
不预期次正规数的实现会如何误解(二进制)指数字段以表示比实际表示的指数小一的指数,因此打印一个值是预期值的一半。这是我对正在发生的事情的猜测。
您可能还可以通过打印来区分错误的值和错误的显示情况,例如 rd * 4
。无论哪种方式,这都应该在正常数字的范围内,所以人们会假设 printf()
特定于次正规数字的错误不会影响它的打印。
至于如何进行,您有多种选择。我最有可能想到的是:
避免次正规数。这可能不切实际,但至少你可以使用
LDBL_MIN
作为你的初始化器,而不是一个最接近次正规long double
. 的常量
忽略这个问题。如果您可以确认这是一个显示问题,而不是错误值问题,那么您可能不需要做任何事情来充分服务于更大的 objective.
修复 NetBSD 的 C 库。假设问题出在
printf()
中,修复可能不会很大,并且库是开源的,就像系统的其余部分一样。提交错误报告并等待其他人修复它。如果您需要及时修复,那么这可能不适合,但如果您有时间等待,那么这对您来说几乎不需要付出任何努力。
已报告给 NetBSD incorrect printf result for subnormal long double values 并在 NetBSD-current
中修复