微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么10/3它在C中是准确的?

参见英文答案 > Why printf round floating point numbers?3个
看看这段代码.
10/3返回3.3333332538604736328125000并且当我在calcutor中乘以3时得到9.99,但是如果通过代码执行相同的操作我得到10.00.
怎么可能?
#include <stdlib.h>
#include <stdio.h>

int main() {

    float v = 10.f/3.f;
    float test = v*3.f;
    printf("10/3 => %25.25f \n (10/3)*3 => %25.25f\n",v,test);
    return 0;
}

这是没有printf的汇编代码,使用认的gcc 7.2.1参数编译:

0000000000400497 <main>:
  400497:       55                      push   rbp
  400498:       48 89 e5                mov    rbp,rsp
  40049b:       f3 0f 10 05 b1 00 00    movss  xmm0,DWORD PTR [rip+0xb1]        # 400554 <_IO_stdin_used+0x4>
  4004a2:       00 
  4004a3:       f3 0f 11 45 fc          movss  DWORD PTR [rbp-0x4],xmm0
  4004a8:       f3 0f 10 4d fc          movss  xmm1,DWORD PTR [rbp-0x4]
  4004ad:       f3 0f 10 05 a3 00 00    movss  xmm0,DWORD PTR [rip+0xa3]        # 400558 <_IO_stdin_used+0x8>
  4004b4:       00 
  4004b5:       f3 0f 59 c1             mulss  xmm0,xmm1
  4004b9:       f3 0f 11 45 f8          movss  DWORD PTR [rbp-0x8],xmm0
  4004be:       b8 00 00 00 00          mov    eax,0x0
  4004c3:       5d                      pop    rbp
  4004c4:       c3                      ret    
  4004c5:       66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
  4004cc:       00 00 00 
  4004cf:       90                      nop

我认为mulss是由cpu功能四舍五入的.

注意,GNU BC程序中的10/3返回3.3333333333333333333333(* 3 => 9.9999),并且在SciLab中返回3.3333333333333334813631(* 3 => 10).

解决方法

你最终得到的结果恰好是10,因为表示恰好是这样的.我对float和double的实现都是一样的.

让我们看一个使用double的例子:

如果我们打印出10./3.在使用%a的十六进制浮点表示法中,我们得到:

0x1.aaaaaaaaaaaabp+1

这与IEEE754双重表示0x401aaaaaaaaaaa匹配.

以上数字归一化为:

0x3.5555555555558

二进制:

11.0101010101010101010101010101010101010101010101011

为了简单起见,让我们添加三次而不是乘以3:

11.0101010101010101010101010101010101010101010101011
+    11.0101010101010101010101010101010101010101010101011
---------------------------------------------------------
    110.1010101010101010101010101010101010101010101010111
+    11.0101010101010101010101010101010101010101010101011
---------------------------------------------------------
   1010.0000000000000000000000000000000000000000000000000

这正好是10.

编辑:

看起来我设法在最后几位数字处理数学.实际总和:

11.0101010101010101010101010101010101010101010101011
+    11.0101010101010101010101010101010101010101010101011
---------------------------------------------------------
    110.1010101010101010101010101010101010101010101010110
+    11.0101010101010101010101010101010101010101010101011
---------------------------------------------------------
   1010.0000000000000000000000000000000000000000000000001

所以它不完全是10,而是最不重要的一点.

我注意到使用float时有类似的区别.

10.f / 3.f用%a打印:

0x1.aaaaaap+1

标准化:

0x3.555554

二进制:

11.0101010101010101010101

然后我们添加

11.0101010101010101010101
+    11.0101010101010101010101
------------------------------
    110.1010101010101010101010
+    11.0101010101010101010101
------------------------------
   1001.1111111111111111111111

再次,由最不重要的位.

至于实际结果如何四舍五入,我不能说.

原文地址:https://www.jb51.cc/c/110318.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐