7

浮動小数点( PDFも)、IEEE-754 を更新し、文字列に変換するときの浮動小数点の丸めに関するこのディスカッションに参加し、いじくり回しました。は同じ。

免責事項: この議論では、IEEE-754 で説明されているように、32 ビットと 64 ビットの浮動小数点に固執したいと思います。拡張浮動小数点 (80 ビット) やクワッド (128 ビット IEEE-754-2008)、その他の標準 (IEEE-854) には興味がありません。

背景: コンピュータは0.1バイナリ表現で表現するのが苦手です。C# では、float はこれを3DCCCCCD内部的に (C# は最も近い値への丸めを使用する) として表し、double は として表し3FB999999999999Aます。0.10000000510 進数(float) と0.1000000000000000124(double) には同じビット パターンが使用されますが、(double) には使用されません0.1000000000000000144

便宜上、次の C# コードはこれらの内部表現を示しています。

string GetHex(float f)
{
    return BitConverter.ToUInt32(BitConverter.GetBytes(f), 0).ToString("X");
}

string GetHex(double d)
{
    return BitConverter.ToUInt64(BitConverter.GetBytes(d), 0).ToString("X");
}

// float
Console.WriteLine(GetHex(0.1F));

// double 
Console.WriteLine(GetHex(0.1));

の場合0.1、同じビット パターンで表される下位の 10 進数はなく、いずれも0.99...99異なるビット表現が生成されます (つまり、内部的に0.999999937生成される浮動小数点数)。3F7FFFFF

私の質問は簡単です。同じバイナリ表現で内部的に格納されている特定の float (または double) の 10 進数の最小値と最大値を見つけるにはどうすればよいですか。

理由: (質問されることは承知しています) .NET を文字列に変換するとき、および文字列から変換するときの丸めのエラーを見つけ、内部の正確な値を見つけ、自分の丸めエラーをよりよく理解するためです。

私の推測では、仮数を取り、残りを削除し、正確な値を取得し、1 つ (仮数ビット) 高くして、平均を計算します。それより下の値は同じビット パターンになります。私の主な問題は、小数部分を整数として取得する方法です(ビット操作は私の最強の資産ではありません)。Jon Skeet の DoubleConverterクラスが役に立つかもしれません。

4

2 に答える 2

6

あなたの質問に答える 1 つの方法は、浮動小数点数の ULP のサイズまたはLast PlaceUnitを見つけることです。少し単純化すると、これは特定の浮動小数点数と次に大きい数の間の距離です。繰り返しますが、少し単純化すると、表現可能な浮動小数点値 x が与えられると、値が (x - 1/2 ulp) と (x + 1/2 ulp) の間の 10 進文字列は、浮動小数点数に変換されるときに x に丸められます。 -ポイント値。

トリックは、(x +/- 1/2 ulp) は表現可能な浮動小数点数ではないため、実際にその値を計算するには、より広い浮動小数点型 (利用可能な場合) または任意の幅の大きな 10 進数を使用する必要があります。または同様のタイプで計算を行います。

ulpのサイズはどうやってわかりますか. 比較的簡単な方法の1つは、おおまかにあなたが提案したものです.C#を知らないので、ここに書かれているのはCっぽい疑似コードです:

float absX = absoluteValue(x);
uint32_t bitPattern = getRepresentationOfFloat(absx);
bitPattern++;
float nextFloatNumber = getFloatFromRepresentation(bitPattern);
float ulpOfX = (nextFloatNumber - absX);

これが機能するのは、x のビット パターンに 1 を追加することは、x の値に ulp を 1 つ追加することに正確に対応するためです。関連する値が非常に近いため、減算で浮動小数点の丸めは発生しません (特に、2 つの数値 x と y が y/2 <= x <= 2y を満たす場合、ieee-754 浮動小数点演算の定理があります。その場合x - yは正確に計算されます)。ここでの唯一の注意事項は次のとおりです。

  1. x がたまたま最大の有限浮動小数点数である場合、これは機能しません (inf明らかに間違っている を返します)。
  2. プラットフォームが段階的アンダーフローを正しくサポートしていない場合 (たとえば、flush-to-zero モードで実行されている組み込みデバイス)、これは x の値が非常に小さい場合には機能しません。

これらの状況のいずれにも該当しないように思われるため、これは目的に応じてうまく機能するはずです。

x の ulp が何であるかがわかったので、x に丸める値の間隔を見つけることができます。ulp(x)/2 は浮動小数点で正確に計算できます。これは、浮動小数点の 2 除算が正確であるためです (ここでも、アンダーフローがなければ)。次に、 x +/- ulp(x)/2 の適切なより大きな浮動小数点型 (doubleに興味がある場合に機能しますfloat) または Big Decimal 型の値を計算するだけでよく、間隔があります。

この説明を通じて、いくつかの単純化した仮定を行いました。これを正確に説明する必要がある場合は、コメントを残してください。機会があれば、少しあいまいなセクションを詳しく説明します.


もう1つは、質問の次のステートメントに注意してください。

0.1 の場合、同じビットパターンで表現される下位の 10 進数はありません。

間違っています。たまたま間違った値を見ているだけです (0.099999 の代わりに 0.999999... -- 簡単なタイプミス)。

于 2009-11-03T16:58:18.620 に答える
1

Python 3.1 は次のようなものを実装しました:変更ログ (少し下にスクロール)バグ レポートを参照してください。

于 2009-11-17T20:22:06.390 に答える