通过C语言中的整数转换进行浮点数比较

我想得到一个确切/准确的答案为什么以下代码打印不同的结果:

#include "stdio.h" int main(void) { int a = 9; int b = 10; printf("%d\n", (double)a / (double)b == 0.9); /* prints 0 */ printf("%d\n", (double)9 / (double)10 == 0.9); /* prints 1 */ return 0; } 

我认为这可能是编译器依赖的,我的是gcc(GCC mingw Windows7)4.8.1和gcc(Debian 4.7.2-5)4.7.2。

非常感谢你!

UPDATE!

我使用和不使用-std = c99选项生成汇编代码,这应该有助于理解这里发生的事情。

没有-std = c99(这给出结果0/1):

  .file "ac" .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "%d\n" .section .text.startup,"ax",@progbits .p2align 4,,15 .globl main .type main, @function main: .LFB11: .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 $16, %esp movl $1, 4(%esp) movl $.LC0, (%esp) call printf movl $1, 4(%esp) movl $.LC0, (%esp) call printf xorl %eax, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE11: .size main, .-main .ident "GCC: (Debian 4.7.2-5) 4.7.2" .section .note.GNU-stack,"",@progbits 

使用-std = c99(这会得到结果1/1):

  .file "ac" .section .rodata .LC1: .string "%d\n" .text .globl main .type main, @function main: .LFB0: .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 $32, %esp movl $9, 28(%esp) movl $10, 24(%esp) fildl 28(%esp) fildl 24(%esp) fdivrp %st, %st(1) movl $1, %edx fldt .LC0 fucomp %st(1) fnstsw %ax sahf jp .L5 fldt .LC0 fucompp fnstsw %ax sahf je .L2 jmp .L3 .L5: fstp %st(0) .L3: movl $0, %edx .L2: movzbl %dl, %eax movl %eax, 4(%esp) movl $.LC1, (%esp) call printf movl $1, 4(%esp) movl $.LC1, (%esp) call printf movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .section .rodata .align 16 .LC0: .long 1717986918 .long -429496730 .long 16382 .ident "GCC: (Debian 4.7.2-5) 4.7.2" .section .note.GNU-stack,"",@progbits 

在C中,允许浮点数运算的精度高于代码指示的精度。
特别是编译时数学(第二行)可以作为long double运行

C11dr§5.2.4.2.29“除了赋值和强制转换(删除所有额外的范围和精度)之外,具有浮动操作数的运算符产生的值和通常算术转换以及浮动常量的值被评估为一种格式,范围和精度可能大于类型所要求的范围。

见上面的@Patricia Shanahan。


[编辑]

如果已定义,请检查FP评估模式

 #include  printf("%d\n", FLT_EVAL_METHOD); 

C11dr§5.2.4.2.29(续)评估格式的使用由FLT_EVAL_METHOD的实现定义值FLT_EVAL_METHOD

-1不确定;

0仅根据类型的范围和精度评估所有操作和常量;

1计算float类型的操作和常量以及double类型的范围和精度,将long double操作和常量计算为long double类型的范围和精度;

2评估long double类型的范围和精度的所有操作和常量。

FLT_EVAL_METHOD的所有其他负值表征实现定义的行为。