#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
。#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
。pi1 是一个预处理符号,会在文本中被替换为一个双精度浮点数。
pi 是一个从双精度浮点数初始化的浮点常量,因此会失去一些精度位(请参阅IEEE754规范)。
更多详情,实际上作为浮点数存储的 pi 是 0x40490625,即 3.1410000324249267578125。pi1 存储为 0x400920C49BA5E354,即 3.1410000000000000142108547152。
pi
作为float
大于3.141
,那么为什么printf
将4*40*pi
转换为125.639999
,暗示一个低于125.64
的值? - chqrlie在C语言中,浮点数常量的类型为double
,除非你添加后缀f
(float)或L
(long double)
因此,在第一部分(4*10*pi
)中,3.141是一个double
值,被转换为float精度并存储在const float pi
中,然后表达式4*10*pi
将在float
精度下进行计算。另一方面,在4*10*pi1
中,该宏直接被替换为字符串,然后从double
中计算,这就是为什么结果不同的原因。
只是为了强调@Joel和@Lưu Vĩnh Phú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
以帮助定位问题。现在看看这些值是如何以不同的方式构建的:
对于4*10*pi
,从FPUs中加载了两个浮点数,而对于4*10*pi1
只加载了一个(没有乘法)。我相信这将导致已经提到的浮点/双精度转换问题。
我不是汇编专家,但我认为这些片段可以帮助理解正在发生的事情,或者至少澄清浮点乘法的两种方法不会导致相同的汇编。
125.639999 125.640000
。 - Joseph Quinseygcc -03
。如果我去掉-O3
,我得到的是125.640001 125.640000
。gcc 版本是 4.1.2。 - Joseph Quinsey