MainPage 〜きまぐれ ぷろぐらま語録〜
 

2024年11月
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24
25
26 27 28 29 30

最近の記事
Blog移転

エアポート2010を見た

花椒油

Steve Jobs,1955-2011

鉄球に無数のとげが付いた武器

M55→M42(T)が欲しい

健康診断done

回転寿司のルール

相模湖リゾート・プレジャー・フ ..

過去ログ 【表示/最小化】
2011年10月
2011年 9月
2011年 8月
2011年 7月
2011年 6月
2011年 5月
2011年 4月
2011年 3月
2011年 2月
2011年 1月
2010年12月
2010年11月
2010年10月
2010年 9月
2010年 8月
2010年 7月
2010年 6月
2010年 5月
2010年 4月
2010年 3月
2010年 2月
2010年 1月
2009年12月
2009年11月
2009年10月
2009年 9月
2009年 8月
2009年 7月
2009年 6月
2009年 5月
2009年 4月
2009年 3月
2009年 2月
2009年 1月
2008年12月
2008年11月
2008年10月
2008年 9月
2008年 6月
2008年 5月
2008年 4月
2008年 3月
2008年 2月
2008年 1月
2007年12月
2007年11月
2007年10月
2007年 9月
2007年 8月
2007年 7月
2007年 6月
2007年 5月
2007年 4月
2007年 3月
2007年 2月
2007年 1月
2006年12月
2006年11月
2006年10月
2006年 9月
2006年 8月
2006年 7月
2006年 6月
2006年 5月

広告欄

 

Blogを移転させました。
新Blogは次のURLです。
https://kerokero.org/wp/




通貨型の備忘録
寝る前に仕事の備忘録。

コンピューターの浮動小数点演算は2進数の丸め誤差が発生する。

簡単に説明すると、
・二進数表現で0.1は十進数表現で0.5のこと。
・二進数表現で0.01は十進数表現で0.25のこと。
・二進数表現で0.11は十進数表現で0.75のこと。
つまり、0以下の各桁の重みは、
1/2,1/4,1/8・・・1/(2^n)
なわけで。

十進数表現の0.1を二進数表現で表そうとしたら、
0.0001100110011・・・(※二進数表現。以下、このように特に断りがなければ十進数表現)
となる。つまり0011が繰り返される循環小数になるわけだ。

でも、無限に循環するわけにはいかないので、その辺のなんやかんやで、
演算誤差が出るわけだ。

つまり、プログラムの世界において、
0.1を10回足した物と、1は必ずしも一致しない。

さらに、やっかいなのが、1000円の消費税を計算しようと、
double x = 0.05f;
double y = 1000f;
double z = ceil(x*y);
ってやると、zには「51」って入ってしまう。

問題の部分は、「double x = 0.05f」で、単精度の浮動小数点の0.05を、
倍精度に代入して演算をすると、単精度で発生した誤差が、
倍精度できちんと計算されるため、
x*yの結果が50をほんのわずか上回った数字になってしまうので、
切り上げたら51になっちゃうわけだ。

※逆に1/3は十進数では、0.3333・・・と循環するけど、
 三進数なら、0.1(※三進数表現)となって、丸く収まる。


このn進数間の誤差を吸収する方法が、固定小数点演算だ。
言語によって、Decimal型とかNumeric型とかCurrency型とか、
いろいろあるけど本質は同じ。

たとえば、0.05を表すには、
5×(10^-2)
みたいに、
x×(10^-y)
って形で、計算される。

これにより二進数の小数点以下の表現における演算誤差を発生させなくしているわけだ。

で、以下、備忘録の本題。
久しぶりなので、すっかり誤差の範囲を忘れていたので、
せっかくなので書き出してみる。

基本的に、これらの型はなので、Currency型=通貨型と
呼ばれることからも分かるように、会計演算で使う型だ。

なので、通貨計算に限って、正しい演算結果を保証できる桁数の値を書き出してみる。
というか、これらの型が内部でどのように状態を遷移させて、
正確な数値演算をしているかの説明。

■足し算
1+1=2 (※つまり、小数点以下が無し)
0.1+0.2=0.3 (※つまり、小数点以下が1桁まで有効)
0.1+0.05=0.15 (※つまり、演算子の右と左オペランドの小数点以下の桁数の大きい物が有効)

■引き算
※足し算と同じ。

■かけ算
1234*2=2468 (※つまり、小数点以下が無し)
1234*0.01=12.34 (※つまり、小数点以下が2桁まで有効)
1234*0.05=61.70 (※つまり、小数点以下が2桁まで有効)
0.01*0.02=0.0002 (※つまり、小数点以下が4桁まで有効)
0.01*0.002=0.00002 (※つまり、小数点以下が5桁まで有効)
まとめると、かけ算の右オペランドの有効な桁数+右オペランドの有効の桁数。

■割り算
会計演算ではなかなか発生しないけど一番ややこしい。
演算結果によって、有効な桁が無限になる。
1/3=0.333333333・・・

ただ、ちゃんと割り切れるならば、
1/10=0.1
0.1/10=0.01
0.01/0.1=0.1
となる。
これは
x×(10^-y)
の表現のyの値(スケール)を元に計算する。
すなわち、演算後の有効な桁数は、
(割られる数のスケール)-(割る数のスケール)。

先の例ならば、
1/10=0.1 (※0-1=-1なので10^-1=0.1まで有効)
0.1/10=0.01 (※-1-1=-2なので10^-2=0.01まで有効)
0.01/0.1=0.1 (※-2-(-1)=-1なので10^-1=0.1まで有効)
でも、先の例があるので、油断はできない。

ちなみに、Javaならば、
BigDecimal a = new BigDecimal(1);
BigDecimal b = new BigDecimal(10);
a.divide(b);//・・・0.1が戻る。
と割り切れればいいけど、割り切れないと、こう:
BigDecimal a = new BigDecimal(1);
BigDecimal b = new BigDecimal(3);
a.divide(b);//表現できない値なので、ArithmeticException例外が発生する。

こんなときは、
a.divide(b, 2, RoundingMode.FLOOR);//0.33
ってやれば、小数点以下第3位を切り捨てて、第2位までが有効になる。

丸めタイプの指定は
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/math/RoundingMode.html
この辺が詳しい。


以上、明日への備忘録。
03:55, Tuesday, Apr 20, 2010 ¦ 固定リンク ¦ 携帯


■コメント

■コメントを書く

※コメントの受け付けは終了しました

△ページのトップへ
 

最新のつぶやき

サイト内検索
カスタム検索

旅行関係の記事等
九州・広島旅行記 2009(かみちゅ!)
大阪出張(KANON)
大阪出張(ハルヒ)
三宅島旅行記'05
三宅島旅行記'08
三宅島旅行記'10
伊豆半島小旅行

最近のコメント

最近のトラックバック

IPv4枯渇時計

携帯で読む
   URLを携帯に送る





[Valid RSS]

Powered by CGI RESCUE