2

float 値が long int に割り当てられた場合、次のコードに問題 (潜在的な未定義の動作) はありますか?

struct timespec t; 
t.tv_nsec = (some float value < 1) * 1E9
4

1 に答える 1

5

変換はコンパイル時に行われます。コンパイラから警告が出るかもしれませんが、浮動小数点定数で整数を初期化することは非常に慣習的であるため、実際にはコードに「問題」はありません。


私が与えた初期化は、単純にするためだけのものでした。コードでは、次のようになります。

struct timespec t; t.tv_nsec = (some float value < 1) * 1E9;

ナノ秒にtv_nsec; 興味深いですが、大きな問題はありません。double は実際には十分な精度を備えているため、大きな問題に遭遇することはありません。それを確認する価値があるかもしれません。それはあなたにとってどれほど重要かによって異なります。

問題があるかどうかを確認するために簡単なプログラムを実行しました。これは実行時の計算であり、コンパイル時の計算ではありませんが、結果は同様になる可能性があることに注意してください。

#include <stdio.h>

int main(void)
{
    for (long l = 0; l < 1000000000; l++)
    {
        double d = l / 1.0E9;
        long r = d * 1E9;
        if (r != l)
            printf("%.9ld: %12.9f != %ld\n", l, d, r);
    }
    return 0;
}

小数値が整数値と一致しない値を出力します。いくつかの大量の出力の小さなセクションは次のとおりです。

031890838:  0.031890838 != 31890837
031890839:  0.031890839 != 31890838
031890840:  0.031890840 != 31890839
031890851:  0.031890851 != 31890850
031890852:  0.031890852 != 31890851
031890853:  0.031890853 != 31890852
031890864:  0.031890864 != 31890863
031890865:  0.031890865 != 31890864
031890866:  0.031890866 != 31890865
031890877:  0.031890877 != 31890876
031890878:  0.031890878 != 31890877
031890879:  0.031890879 != 31890878
031890890:  0.031890890 != 31890889

すべての値に問題があるわけではありませんがwc -l、1,000,000,000 個の値のうち 17,075,957 個 (または値の約 1.7%) を不一致で記録しています。これは Mac OS X 10.7.4 上の GCC 4.1.2 (Apple 提供) でした。GCC 4.7.0 でも同じ結果が得られました。データの生成には約 30 秒かかりました。

Kernighan と Plauger による「The Elements of Programming Style」からの私のお気に入りの引用の 1 つは、次のとおりです。

  • ある賢明なプログラマーは、「浮動小数点数は小さな砂の山に似ている。1 つ動かすたびに、砂が少し減り、汚れが少し増えます。

これは問題をよく示しています。


些細な変更でエラー率が 0 になることに注意してください。

long r = d * 1E9 + 0.5;

たぶん、マクロを使用する必要があります。

#define NANOSECONDS(x) ((x) * 1E9 + 0.5)

long r = NANOSECONDS(d);

より小さな加法定数を使用できます。0.1 はエラー率も 0 に減らしました。

于 2012-05-24T02:51:27.377 に答える