3

いくつかのパーリン ノイズ関数をいじろうとしているときに奇妙なバグに遭遇しました。突然、すべての通話の途中でオフ値が表示されました。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 を返します)。

このような結果を見た人はいますか?

4

2 に答える 2

5

最終編集: これはほぼ確実に GCC または glibc のバグです。コード内の別の場所で fmod を呼び出す関数を宣言するだけで (その関数が呼び出されなくても)、問題は解消されます。

-fno-builtinsこれを回避するには、コンパイラに渡すことをお勧めします。それは私のためにそれを修正するようです。


cygwin の GCC 4.5.3 でこれを再現できます。

iこれは、変数が非 constの場合にのみ発生します [編集:おそらく、最初の除算の結果を格納するために一時変数を使用するようコンパイラーに奨励しているためです)。テストする私のさらに単純な C プログラム:

#include <stdio.h>

#include <math.h>

int main()
{
    int i = 512;
    printf("%f %f\n", fmod(i/102.4,1.f), fmod(i/102.4,1.f));
    printf("%f %f\n", 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 %f\12\0"
    .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 "\0"
    .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 "\0"
    .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\0"
    .byte   0x4
    .ascii "test.cpp\0"
    .ascii "/home/martin\0"
    .long   Ltext0
    .long   Letext0
    .secrel32   Ldebug_line0
    .uleb128 0x2
    .byte   0x4
    .byte   0x7
    .ascii "unsigned int\0"
    .uleb128 0x2
    .byte   0x1
    .byte   0x6
    .ascii "char\0"
    .uleb128 0x2
    .byte   0x1
    .byte   0x6
    .ascii "signed char\0"
    .uleb128 0x2
    .byte   0x1
    .byte   0x8
    .ascii "unsigned char\0"
    .uleb128 0x2
    .byte   0x2
    .byte   0x5
    .ascii "short int\0"
    .uleb128 0x2
    .byte   0x2
    .byte   0x7
    .ascii "short unsigned int\0"
    .uleb128 0x2
    .byte   0x4
    .byte   0x5
    .ascii "int\0"
    .uleb128 0x2
    .byte   0x8
    .byte   0x5
    .ascii "long long int\0"
    .uleb128 0x2
    .byte   0x8
    .byte   0x7
    .ascii "long long unsigned int\0"
    .uleb128 0x2
    .byte   0x4
    .byte   0x5
    .ascii "long int\0"
    .uleb128 0x2
    .byte   0x4
    .byte   0x7
    .ascii "long unsigned int\0"
    .uleb128 0x2
    .byte   0x8
    .byte   0x4
    .ascii "double\0"
    .uleb128 0x2
    .byte   0x4
    .byte   0x4
    .ascii "float\0"
    .uleb128 0x2
    .byte   0xc
    .byte   0x4
    .ascii "long double\0"
    .uleb128 0x3
    .byte   0x1
    .ascii "main\0"
    .byte   0x1
    .byte   0x5
    .long   0x98
    .long   LFB7
    .long   LFE7
    .secrel32   LLST0
    .uleb128 0x4
    .long   LBB2
    .long   LBE2
    .uleb128 0x5
    .ascii "i\0"
    .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\0"
    .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); }、呼び出しを渡すと問題が解決します。]

于 2012-08-05T08:20:07.097 に答える
3

これはgccやライブラリのバグではありません。これは、不正確な浮動小数点表現の結果にすぎません。

i=512;
cout << i << ","  << fmod(i/102.4,1.f) << "," << fmod(i/102.4,1.f) << endl;

数学的な結果512/102.4は正確に5です。ただし102.4、2進浮動小数点で正確に表すことはできないため、渡される値はfmod正確に5.0、またはその少し上または下のいずれかになります。

除算の結果が、たとえば、の場合は、4.99999999fmod(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
于 2012-08-05T09:00:19.263 に答える