#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
答案 0 :(得分:6)
pi1是预处理程序符号,并以文本形式替换为double。
pi是一个从double初始化的浮点常量,因此会丢失一些精度位(参见IEEE754规范)。
有关更多详细信息,pi作为float实际上存储为0x40490625,即3.1410000324249267578125。 pi1存储为0x400920C49BA5E354,即3.1410000000000000142108547152
答案 1 :(得分:2)
因此,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来比较它们。