为什么两个计算给出不同的答案?

时间:2014-01-31 16:02:23

标签: c floating-point constants c-preprocessor

#include<stdio.h>

#define pi1 3.141

const float pi = 3.141;

int main()    
{    
    printf("%f %f",4*10*pi, 4*10*pi1);  
}

输出(在我的机器上)是125.639999 125.640000

4 个答案:

答案 0 :(得分:6)

pi1是预处理程序符号,并以文本形式替换为double。

pi是一个从double初始化的浮点常量,因此会丢失一些精度位(参见IEEE754规范)。

有关更多详细信息,pi作为float实际上存储为0x40490625,即3.1410000324249267578125。 pi1存储为0x400920C49BA5E354,即3.1410000000000000142108547152

答案 1 :(得分:2)

除非附加后缀f(float)或lf(long double)

,否则C浮点常量的类型为double

因此,3.141被截断为3.141f并存储到pi,然后pi在表达式4*10*pi中从float升级为double,而4*10*pi1则直接替换为字符串然后从double计算。这就是为什么它不同

答案 2 :(得分:0)

为了强化@Joel和@LưuVĩnhPhúc的回复,请考虑以下代码段

#include<stdio.h>

#define pi1 3.141

const float pi = 3.141;

int main()
{

printf("foo"); // Just to mark assembly output

printf("4*10*pi == %f\n", 4*10*pi);

printf("4*10*pi1 == %f\n", 4*10*pi1);

float a = 4*10*pi;
float b = 4*10*pi1;
printf("%f %f\n", a, b);

}

由gcc(4.8.1)生成的程序集:

    .file   "c.c"
    .globl  _pi
    .section .rdata,"dr"
    .align 4
_pi:
    .long   1078527525
    .def    ___main;    .scl    2;  .type   32; .endef
LC0:
    .ascii "foo\0"
LC3:
    .ascii "4*10*pi == %f\12\0"
LC5:
    .ascii "4*10*pi1 == %f\12\0"
LC7:
    .ascii "%f %f\12\0"
    .text
    .globl  _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
LFB6:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $48, %esp
    call    ___main
    movl    $LC0, (%esp)
    call    _printf

    flds    LC1
    flds    LC2
    fmulp   %st, %st(1)
    fstpl   4(%esp)
    movl    $LC3, (%esp)    
    call    _printf

    fldl    LC4
    fstpl   4(%esp)
    movl    $LC5, (%esp)
    call    _printf

    flds    LC1
    flds    LC2
    fmulp   %st, %st(1)
    fstps   44(%esp)
    movl    LC6, %eax
    movl    %eax, 40(%esp)
    flds    40(%esp)
    flds    44(%esp)
    fxch    %st(1)
    fstpl   12(%esp)
    fstpl   4(%esp)
    movl    $LC7, (%esp)
    call    _printf

    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE6:
    .section .rdata,"dr"
    .align 4
LC1:
    .long   1078527525
    .align 4
LC2:
    .long   1109393408
    .align 8
LC4:
    .long   -1030792151
    .long   1079994613
    .align 4
LC6:
    .long   1123764142
    .ident  "GCC: (GNU) 4.8.1"
    .def    _printf;    .scl    2;  .type   32; .endef

我添加了额外的printfs来帮助定位事物。现在看看te值是如何以不同的方式构建的:

对于4*10*pi,从FPU加载两个浮点数,而4*10*pi1只加载一个浮点数(没有乘法)。我相信这将导致已经引用的浮动/双转换问题。

我不是汇编专家,但我认为这些片段可以帮助理解正在发生的事情,或者至少澄清浮动乘法的两种方法不会导致相同的汇编。

答案 3 :(得分:-3)

有趣。请提供打印输出以及编译器选项。我的预感:pi1由预处理器通过字符串替换插入。编译器选择它并在编译时用常量替换它。然而,它并没有采用'pi'进行相同的优化,可能取决于您正在应用的优化级别。因此,第一个数字是在运行时计算的,这可能导致略微偏离。

作为一般规则,永远不要指望两个浮点数相等,总是使用epsilon来比较它们。