fmod 返回不一致的值
fmod returns inconsistent value
在尝试使用一些柏林噪声函数时遇到了一个奇怪的错误。突然之间,我在所有电话中间都得到了一个偏离值。将其追溯到 fmod(( 中不一致的返回值。
i=512;
cout << i << "," << fmod(i/102.4,1.f) << "," << fmod(i/102.4,1.f) << endl;
我希望得到以下输出。
512,0,0
但我没有。我明白了。
512,0,1
更奇怪的是,如果我多次调用 cout 线,错误会在以后的运行中消失。
512,0,1
512,0,0
512,0,0
将值硬编码到函数中(将所有"y"替换为"512"(会产生正确的结果(始终返回 0(。
有没有人见过这样的结果?
最终编辑:这几乎可以肯定是GCC或glibc中的一个错误。 简单地声明一个在代码中的其他地方调用 fmod 的函数(即使该函数没有被调用(就会使问题消失。
我建议将-fno-builtins
传递给编译器来解决此问题。 塔斯似乎为我解决了它。
我能够在 GCC 4.5.3 中为 cygwin 重现这一点。
仅当i
变量是非常量变量时,才会发生这种情况[编辑:可能是因为它鼓励编译器使用临时变量来存储初始除法的结果(。我更简单的C程序测试:
#include <stdio.h>
#include <math.h>
int main()
{
int i = 512;
printf("%f %fn", fmod(i/102.4,1.f), fmod(i/102.4,1.f));
printf("%f %fn", fmod(i/102.4,1.f), fmod(i/102.4,1.f));
}
哪些输出:
0.000000 1.000000
0.000000 0.000000
我尝试查看 asm 输出,但我的 x87-foo 很弱。 其他人能看出问题所在吗? 在此期间,我会继续寻找:
.file "test.cpp"
.section .debug_abbrev,"dr"
Ldebug_abbrev0:
.section .debug_info,"dr"
Ldebug_info0:
.section .debug_line,"dr"
Ldebug_line0:
.text
Ltext0:
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC3:
.ascii "%f %f12 "
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB7:
.file 1 "test.cpp"
.loc 1 6 0
pushl %ebp
LCFI0:
movl %esp, %ebp
LCFI1:
andl $-16, %esp
LCFI2:
subl $64, %esp
LCFI3:
.loc 1 6 0
call ___main
LBB2:
.loc 1 7 0
movl $512, 60(%esp)
.loc 1 8 0
fildl 60(%esp)
fldl LC0
fdivrp %st, %st(1)
fld1
fld %st(1)
L2:
fprem
fnstsw %ax
sahf
jp L2
fstp %st(1)
fucomi %st(0), %st
jp L5
fucomi %st(0), %st
je L6
fstp %st(0)
jmp L4
L5:
fstp %st(0)
L4:
fld1
fstpl 8(%esp)
fstpl (%esp)
call _fmod
jmp L3
L6:
fstp %st(1)
L3:
fstpl 40(%esp)
fildl 60(%esp)
fldl LC0
fdivrp %st, %st(1)
fld1
fstpl 8(%esp)
fstpl (%esp)
call _fmod
fldl 40(%esp)
fstpl 12(%esp)
fstpl 4(%esp)
movl $LC3, (%esp)
call _printf
.loc 1 9 0
fildl 60(%esp)
fldl LC0
fdivrp %st, %st(1)
fld1
fstpl 8(%esp)
fstpl (%esp)
call _fmod
fstpl 32(%esp)
fildl 60(%esp)
fldl LC0
fdivrp %st, %st(1)
fld1
fstpl 8(%esp)
fstpl (%esp)
call _fmod
fldl 32(%esp)
fstpl 12(%esp)
fstpl 4(%esp)
movl $LC3, (%esp)
call _printf
LBE2:
movl $0, %eax
.loc 1 10 0
leave
LCFI4:
ret
LFE7:
.section .rdata,"dr"
.align 8
LC0:
.long -1717986918
.long 1079613849
.section .debug_frame,"dr"
Lframe0:
.long LECIE0-LSCIE0
LSCIE0:
.long 0xffffffff
.byte 0x1
.ascii " "
.uleb128 0x1
.sleb128 -4
.byte 0x8
.byte 0xc
.uleb128 0x4
.uleb128 0x4
.byte 0x88
.uleb128 0x1
.align 4
LECIE0:
LSFDE0:
.long LEFDE0-LASFDE0
LASFDE0:
.secrel32 Lframe0
.long LFB7
.long LFE7-LFB7
.byte 0x4
.long LCFI0-LFB7
.byte 0xe
.uleb128 0x8
.byte 0x85
.uleb128 0x2
.byte 0x4
.long LCFI1-LCFI0
.byte 0xd
.uleb128 0x5
.byte 0x4
.long LCFI4-LCFI1
.byte 0xc5
.byte 0xc
.uleb128 0x4
.uleb128 0x4
.align 4
LEFDE0:
.section .eh_frame,"w"
Lframe1:
.long LECIE1-LSCIE1
LSCIE1:
.long 0x0
.byte 0x1
.ascii " "
.uleb128 0x1
.sleb128 -4
.byte 0x8
.byte 0xc
.uleb128 0x4
.uleb128 0x4
.byte 0x88
.uleb128 0x1
.align 4
LECIE1:
LSFDE3:
.long LEFDE3-LASFDE3
LASFDE3:
.long LASFDE3-Lframe1
.long LFB7
.long LFE7-LFB7
.byte 0x4
.long LCFI0-LFB7
.byte 0xe
.uleb128 0x8
.byte 0x85
.uleb128 0x2
.byte 0x4
.long LCFI1-LCFI0
.byte 0xd
.uleb128 0x5
.byte 0x4
.long LCFI4-LCFI1
.byte 0xc5
.byte 0xc
.uleb128 0x4
.uleb128 0x4
.align 4
LEFDE3:
.text
Letext0:
.section .debug_loc,"dr"
Ldebug_loc0:
LLST0:
.long LFB7-Ltext0
.long LCFI0-Ltext0
.word 0x2
.byte 0x74
.sleb128 4
.long LCFI0-Ltext0
.long LCFI1-Ltext0
.word 0x2
.byte 0x74
.sleb128 8
.long LCFI1-Ltext0
.long LCFI4-Ltext0
.word 0x2
.byte 0x75
.sleb128 8
.long LCFI4-Ltext0
.long LFE7-Ltext0
.word 0x2
.byte 0x74
.sleb128 4
.long 0x0
.long 0x0
.section .debug_info,"dr"
.long 0x13a
.word 0x2
.secrel32 Ldebug_abbrev0
.byte 0x4
.uleb128 0x1
.ascii "GNU C++ 4.5.3 "
.byte 0x4
.ascii "test.cpp "
.ascii "/home/martin "
.long Ltext0
.long Letext0
.secrel32 Ldebug_line0
.uleb128 0x2
.byte 0x4
.byte 0x7
.ascii "unsigned int "
.uleb128 0x2
.byte 0x1
.byte 0x6
.ascii "char "
.uleb128 0x2
.byte 0x1
.byte 0x6
.ascii "signed char "
.uleb128 0x2
.byte 0x1
.byte 0x8
.ascii "unsigned char "
.uleb128 0x2
.byte 0x2
.byte 0x5
.ascii "short int "
.uleb128 0x2
.byte 0x2
.byte 0x7
.ascii "short unsigned int "
.uleb128 0x2
.byte 0x4
.byte 0x5
.ascii "int "
.uleb128 0x2
.byte 0x8
.byte 0x5
.ascii "long long int "
.uleb128 0x2
.byte 0x8
.byte 0x7
.ascii "long long unsigned int "
.uleb128 0x2
.byte 0x4
.byte 0x5
.ascii "long int "
.uleb128 0x2
.byte 0x4
.byte 0x7
.ascii "long unsigned int "
.uleb128 0x2
.byte 0x8
.byte 0x4
.ascii "double "
.uleb128 0x2
.byte 0x4
.byte 0x4
.ascii "float "
.uleb128 0x2
.byte 0xc
.byte 0x4
.ascii "long double "
.uleb128 0x3
.byte 0x1
.ascii "main "
.byte 0x1
.byte 0x5
.long 0x98
.long LFB7
.long LFE7
.secrel32 LLST0
.uleb128 0x4
.long LBB2
.long LBE2
.uleb128 0x5
.ascii "i "
.byte 0x1
.byte 0x7
.long 0x98
.byte 0x2
.byte 0x74
.sleb128 60
.byte 0x0
.byte 0x0
.byte 0x0
.section .debug_abbrev,"dr"
.uleb128 0x1
.uleb128 0x11
.byte 0x1
.uleb128 0x25
.uleb128 0x8
.uleb128 0x13
.uleb128 0xb
.uleb128 0x3
.uleb128 0x8
.uleb128 0x1b
.uleb128 0x8
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x1
.uleb128 0x10
.uleb128 0x6
.byte 0x0
.byte 0x0
.uleb128 0x2
.uleb128 0x24
.byte 0x0
.uleb128 0xb
.uleb128 0xb
.uleb128 0x3e
.uleb128 0xb
.uleb128 0x3
.uleb128 0x8
.byte 0x0
.byte 0x0
.uleb128 0x3
.uleb128 0x2e
.byte 0x1
.uleb128 0x3f
.uleb128 0xc
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x1
.uleb128 0x40
.uleb128 0x6
.byte 0x0
.byte 0x0
.uleb128 0x4
.uleb128 0xb
.byte 0x1
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x1
.byte 0x0
.byte 0x0
.uleb128 0x5
.uleb128 0x34
.byte 0x0
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x2
.uleb128 0xa
.byte 0x0
.byte 0x0
.byte 0x0
.section .debug_pubnames,"dr"
.long 0x17
.word 0x2
.secrel32 Ldebug_info0
.long 0x13e
.long 0x10d
.ascii "main "
.long 0x0
.section .debug_pubtypes,"dr"
.long 0xe
.word 0x2
.secrel32 Ldebug_info0
.long 0x13e
.long 0x0
.section .debug_aranges,"dr"
.long 0x1c
.word 0x2
.secrel32 Ldebug_info0
.byte 0x4
.byte 0x0
.word 0x0
.word 0x0
.long Ltext0
.long Letext0-Ltext0
.long 0x0
.long 0x0
.def _fmod; .scl 2; .type 32; .endef
.def _printf; .scl 2; .type 32; .endef
[编辑:请注意,总是对fmod的第一个调用返回奇怪的结果(以后永远不会(。 正在从右到左评估 fmod 调用。
[编辑2:定义一个函数,double my_fmod(double a, double b) { return fmod(a, b); }
并通过调用传递,使问题消失。
这不是 gcc 或库错误。这只是不精确的浮点表示的结果。
i=512;
cout << i << "," << fmod(i/102.4,1.f) << "," << fmod(i/102.4,1.f) << endl;
512/102.4
的数学结果正好是 5。但是102.4
不能用二进制浮点精确地表示,所以传递给fmod
的值可以正好5.0
,也可以略高于或低于它。
如果除法的结果是,比如说,4.99999999
,那么fmod(i/102.4,1.f)
将返回0.99999999
,这很可能在输出时四舍五入为1
。
尝试更精确地显示值。
您需要修改代码,使其允许的值比预期值略小。 由于fmod()
是一个不连续的函数,它可以极大地放大这种差异。
此程序:
#include <iostream>
#include <iomanip>
#include <cmath>
int main(void) {
int i = 512;
std::cout << i << ","
<< std::setprecision(20) << fmod(i/102.4,1.f)
<< "," << fmod(i/102.4,1.f) << std::endl;
return 0;
}
在我的系统上产生此输出:
512,0,0.99999999999999977796
- 大于65535的C++数组[size]引发不一致的溢出
- 为什么模板类中的对象不能返回值
- C++Brute Force攻击函数不会返回结果
- 我可以使用什么来停止循环而不是"返回 0"?
- 在 C++ 中访问数组负索引处的内存不会返回垃圾
- 在 C++(和 C)中进行类型转换时明显不一致
- 填充上编译器生成的复制构造函数之间的不一致
- 犰狳的 print() 方法和 cout 在从 Rcpp 调用时顺序不一致
- 从 cin 读取不会返回整个输入字符串
- GetTokenInformation 在非提升时不会返回所有特权的雕像
- CreateDIBSection为同一图像返回不一致的位图位值
- 在 Qml 中从 QSqlTableModel 中删除单行时视图不一致
- 从 C++ 函数与 Python 函数返回的不一致值用于偏斜正态分布
- void 函数中的指针参数返回不一致的值
- 为什么函数的返回类型与实际句子不一致?
- Visual C++ 和 gcc 之间从 std::isblank 返回不一致.哪一个错了
- 与在C 中返回向量的行为不一致
- CPPCheck返回不一致的结果
- fmod 返回不一致的值
- 与lambda尾随返回类型不一致