6

次のコード スニペットを検討してください。

float num = 281.583f;
int amount = (int) Math.round(num*100f);
float rounded = amount/100.0f;
double dblPrecision = rounded;
double dblPrecision2 = num;
System.out.println("num : " + num + " amount: " + amount + " rounded: " + rounded + " dbl: " + dblPrecision + " dbl2: " + dblPrecision2);

私が得る出力は

num : 281.583 amount: 28158 rounded: 281.58 dbl: 281.5799865722656 dbl2: 281.5830078125

浮動小数点数が double 変数に割り当てられたときに近似があるのはなぜですか?

4

6 に答える 6

6

近似は、小数をに変換するときに実際に行われますfloat。驚かれるかもしれませんが、PCでは浮動小数点数として正確281.583に表すことはできません。これは、浮動小数点数がPCで2進数の合計として表されるために発生します。、および正確に変換できますが、変換できません。0.50.250.1250.583

フロート(およびダブル)は、として表されます。Σ( 1/2^i*Bi )ここで、Biはi番目のビット(0|1)です。0.625 = 1/2 + 1/4例えば。問題は、すべての小数が2進小数のfinitie合計に変換できるわけではないということです。

この数値の変換方法は次のとおりです(最初の行は列の定義です)。

i|  *2 and trim|    Bit value|  (2^-1)*bit
    0,583       
1   1,166   1   0,5
2   0,332   0   0
3   0,664   0   0
4   1,328   1   0,0625
5   0,656   0   0
6   1,312   1   0,015625
7   0,624   0   0
8   1,248   1   0,00390625
9   0,496   0   0
10  0,992   0   0
11  1,984   1   0,000488281
12  1,968   1   0,000244141
13  1,936   1   0,00012207
14  1,872   1   6,10352E-05
15  1,744   1   3,05176E-05
16  1,488   1   1,52588E-05
17  0,976   0   0
18  1,952   1   3,8147E-06
19  1,904   1   1,90735E-06
        SUM=    0,582998276
于 2010-11-11T12:42:39.300 に答える
4

浮動小数点数は2 進数の分数であるため、おおよその 10 進数しか表すことができません。ソース コード内のリテラル281.583fが IEEE 754 float 値に解析されると、概算が行われます。

フロート自体で、これはprintln印刷されているため、光沢があります

引数の値を隣接する float 型の値と一意に区別するために必要な数の桁数だけです。

多くの場合、これはリテラルの 10 進数値が出力されることを意味します。ただし、値を a に割り当てると、double通常、「 double 型の隣接する値」は type の値よりもはるかに近いfloatため、近似された float の真の値が表示されます。

詳細については、浮動小数点ガイドを参照してください。

于 2010-11-11T12:59:08.083 に答える
0

The floats and doubles actually have the same value internally; they are just printed differently. Add these lines to your program to view them in hex:

System.out.printf("num:           %a\n",num);
System.out.printf("dblPrecision2: %a\n",dblPrecision2);

System.out.printf("rounded:       %a\n",rounded);
System.out.printf("dblPrecision:  %a\n",dblPrecision);

This prints

num:           0x1.19954p8
dblPrecision2: 0x1.19954p8
rounded:       0x1.19947ap8
dblPrecision:  0x1.19947ap8

num = dblPrecision2 and rounded = dblPrecision.

Now 0x1.19954p8 = 100011001.100101010100 = 281.5830078125, and 0x1.19947ap8 = 100011001.1001010001111010 = 281.579986572265625. All that is happening is that they are getting rounded differently upon printing (floats are rounded to a smaller number of digits than doubles).

于 2010-11-11T21:53:45.443 に答える
0

私が理解しているように、あなたの懸念は、なぜこのコード...

float f = 281.583f;
System.out.println(f);
System.out.println((double) f);

...版画

281.583
281.5830078125

(倍精度の方が正確です! )

これが理由です...

(で与えられる、 を438ccaa0表すビットの 16 進形式) をフォームhereにフィードします。フロートが実際には として表されていることがわかります。(@Michael Borgwardt は、そのように印刷されない理由に答えます。)281.583fInteger.toHexString(Float.floatToRawIntBits(281.583f))281.58301

フロートとして表される場合は、そう281.583が印刷されています。281.58301しかし281.58301、double に変換すると、実際にはよりも281.58301281.583!に近づけることができます。

281.58300781250000上記の Web ページの計算を見ると、値が出力されていることがわかる理由に限りなく近づくことができます281.5830078125

于 2010-11-11T13:44:41.457 に答える
0

概算はずっとそこにあります。double が余分なものを表示するのに十分な余分なビットを与えるだけです。

たとえば、281.583 は 2 進数です (桁数は多いが、倍精度には達しません): 100011001.1001_0101_0011_1111_0111_1100_1110_1101_1001...

Float では約 23 ビット、double では約 52 ビットが許容されます。(正確には思い出せません) 100011001.1001_0101_0011_11 は 10 進数で 281.582946777 です。

参考までに、単精度では約 7 桁、倍精度では約 16 桁まで格納されます。これにはすべての数値が含まれているため、 float の精度よりも約 1 桁少ないだけです。

于 2010-11-11T12:58:57.633 に答える
0

つまり、本当に必要な場合を除き、float を使用しないでください。精度が失われ、ほとんど節約できません。double を使用すると、多くの悲しみを救うことができます。

double num = 281.583;
long amount = (long) (num*100);
double rounded = (double) amount/100;
double dblPrecision = rounded;
double dblPrecision2 = num;

版画

num : 281.583 amount: 28158 rounded: 281.58 dbl: 281.58 dbl2: 281.583
于 2010-11-11T17:31:09.610 に答える