質問

C89では、floor()はdoubleを返します。以下の機能が保証されていますか?

double d = floor(3.0 + 0.5);
int x = (int) d;
assert(x == 3);

懸念は、floorの結果がIEEE 754で正確に表現できない可能性があることです。したがって、dは2.99999のようになり、xは2になります。

この質問に対する答えがイエスであるためには、intの範囲内のすべての整数がdoubleとして正確に表現可能でなければならず、floorは常に正確に表現された値を返さなければなりません。

役に立ちましたか?

解決

浮動小数点型が必要な仮数ビットをサポートしている場合、すべての整数は正確な浮動小数点表現を持つことができます。 double は仮数に53ビットを使用するため、32ビットの int をすべて正確に格納できます。結局のところ、指数がゼロの仮数として値を設定することができます。

他のヒント

floor()の結果が正確に表現できない場合、dの値はどうなると思いますか?確かに、変数内の浮動小数点数の表現を取得した場合、定義上、正確に表現できるのではないでしょうか? d ...の表現を取得しました

(さらに、Mehrdadの答えは32ビット整数に対して正しいです。64ビットの倍精度のおよび 64ビット整数を持つコンパイラーでは、当然、より多くの問題があります...)

編集:「floor()の理論的な結果、つまり引数以下の最大整数値」は、intとして表現できない可能性があることを意味します。確かにそうです。 intが32ビットのシステムでこれを表示する簡単な方法:

int max = 0x7fffffff;
double number = max;
number += 10.0;
double f = floor(number);
int oops = (int) f;

浮動小数点から整数への変換の際にCが何をするかを思い出すことはできません...しかし、ここで起こります。

編集:他にも考慮すべき興味深い状況があります。 C#のコードと結果は次のとおりです。Cでは少なくとも同様のことが起こると思います。C#では、 double は64ビットと定義されているため、長い

using System;
class Test
{
    static void Main()
    {
        FloorSameInteger(long.MaxValue/2);
        FloorSameInteger(long.MaxValue-2);
    }

    static void FloorSameInteger(long original)
    {
        double convertedToDouble = original;
        double flooredToDouble = Math.Floor(convertedToDouble);
        long flooredToLong = (long) flooredToDouble;

        Console.WriteLine("Original value: {0}", original);
        Console.WriteLine("Converted to double: {0}", convertedToDouble);
        Console.WriteLine("Floored (as double): {0}", flooredToDouble);
        Console.WriteLine("Converted back to long: {0}", flooredToLong);
        Console.WriteLine();
    }
}

結果:

  

元の値:4611686018427387903
  ダブルに変換:   4.61168601842739E + 18
フロア(ダブル):4.61168601842739E + 18
  ロングに戻された:   4611686018427387904
  
  元の値:9223372036854775805
  ダブルに変換:   9.22337203685478E + 18
フロア(ダブル):9.22337203685478E + 18
  ロングに戻された:   -9223372036854775808

言い換えれば:

(long) floor((double) original)

は常に original と同じではありません。これは驚くべきことではありません-doubleよりも長い値があり(NaN値が与えられている)、多くのdoubleは整数ではないため、すべてのlongが正確に表現できるとは期待できません。ただし、すべての32ビット整数は、 倍精度として表現可能です。

質問したいことについて少し混乱していると思います。 floor(3 + 0.5)は、3、0.5、およびそれらの合計が実際の浮動小数点形式ですべて正確に表現できるため、あまり良い例ではありません。 floor(0.1 + 0.9)はより良い例であり、ここでの本当の問題は、 floor の結果が正確に表現できるかどうかではなく、数字の不正確さ を呼び出す前に floor を呼び出すと、すべての数値が正確だった場合に、予想とは異なる戻り値が返されます。この場合、答えはイエスだと思いますが、それは特定の数字に大きく依存します。

このアプローチが悪い場合は、このアプローチを批判するように他の人に勧めますが、考えられる回避策の1つは、(1.0 + 0x1p-52)または floor (おそらく nextafter を使用した方が良いでしょう)。これにより、数値の最後の2進数の場所でエラーが発生すると、整数値ではなく真下に落ちる場合がありますが、多くの操作で蓄積されたエラーは考慮されません。そのレベルの数値の安定性/正確さが必要な場合は、詳細な分析を行うか、数値を正しく処理できる任意精度または正確な数学ライブラリを使用する必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top