NetBSD长期双重麻烦

时间:2016-01-29 17:19:23

标签: c floating-point netbsd

我的代码很简单:

 #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中的VM):

 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

FYI

/usr/include/x86/float.hLDBL_MIN定义为3.3621031431120935063E-4932L并且此值大于printf结果。

2 个答案:

答案 0 :(得分:3)

  

/usr/include/x86/float.hLDBL_MIN定义为3.3621031431120935063E-4932L并且此值大于printf结果。

LDBL_MINlong double类型的最小正规范化值。类型可以代表较小的数字,它们只是次正常。

我只能推测NetBSD上问题的本质,但主要有两种可能:

  1. 编译器将初始化常量转换为与请求值相距较远(相对意义上)的次正规数。

  2. 这个数字被翻译得很好(但结果仍然是次正常的),而且NetBSD的printf()对于次正规数是错误的,或者至少对于这个数字来说是错误的。

  3. 打印的数字是您预期的一半这一事实表明long double表示中的(二进制)指数存在问题。鉴于IEEE格式的次正规数的细节,很容易想象一个不预期次正规数的printf()实现如何误解(二进制)指数字段以表示比实际表示的指数少一个的指数,因此要打印一个值为预期值的一半。这将是我对正在发生的事情的猜测。

    您也可以通过打印来区分错误的值和错误的显示案例,例如rd * 4。这应该在正常数字的范围内,因此可以假设特定于次正规数的printf()错误不会影响打印它。

    至于如何继续,你有几个选择。最可能发生在我身上的是:

    1. 避免使用次正规数。这可能不切实际,但至少可以使用LDBL_MIN作为初始化程序而不是与次正规long double最接近的常量。

    2. 忽略此问题。如果您可以确认这是一个显示问题,而不是错误值问题,那么您可能不需要做任何事情来充分服务于更大的目标。

    3. 修复NetBSD的C库。假设问题出现在printf()中,修复程序可能不会很大,并且库是开源的,就像系统的其他部分一样。

    4. 提交错误报告并等待其他人修复。如果你需要及时修复,那么这可能不合适,但是如果你有时间等待,那么你需要付出很少的努力。

答案 1 :(得分:1)

向NetBSD报告 incorrect printf result for subnormal long double values  并在NetBSD-current

中修复