«前の日(11-05) 最新 次の日(11-07)» 追記

ema log


2006年11月06日 この日を編集

_ [最近] iTMS

Homework contact L.D.K Lounge Designers Killer

ついに手を出してしまいました。

とりあえず、1500 円のカードを買ってきてたのをようやく使ってみたのですが、スグになくなりそうです。危ないよ。

でも、忌野清志郎とかつまみ食いした後だから、アルバム単位で買うためにはカードを買ってこなければ!(以下、無限ループ)。DAFT PUNK の Homework とか思わず買いそうになりました。Black on Black を聞きたくなったので、カードは買い足しますが。Fantastic Plastic Machine も久しぶりに聞くと良いなぁ…欲しいなぁ…

基本的には、ブックオフ、Disc JJ 巡りなどの方が安くすみそうです。

Capsule 良いよ、Capsule。どしどし買っちゃいそうですよ。

バトンは余り好きではないので、これで回答に変えさせてください。

雨の日は不調気味。

悔しいので、PandoraThe Dillinger Escape Plan かけながら寝ます。

本日のツッコミ(全2件) [ツッコミを入れる]

_ MKT [1500円出してCD一枚買ったのと一緒、とか考えると、すぐ無くなるのも気にならないさ……と、ついさっき久しぶりに30..]

_ ema [カードだとまぁ、使用額の制限が効くので止めれますけどねw]


2007年11月06日 明日,勝手な勉強会「ベクタグラフィックス入門」をやります この日を編集

_ [最近] 明日,勝手な勉強会「ベクタグラフィックス入門」をやります

題目
ベクタグラフィックス入門 -Inkscape の使い方-
時間
15:00〜
場所
僕のいる研究室
発表者
ema
概要
Bitmap vs Vector,SVG,Inkscape の使い方,ブーリアン操作,トレース

ご自由にご参加ください。

発表スライド

OOo Impress 形式
PDF 形式

IPA フォント を使用しています。

ネット中継

ごめんなさい,諸般の都合により一週間延期します m(__)m


2009年11月06日 この日を編集

_ [Programming] 浮動小数点(IEEE 754, 32bit 単精度)について

を受けて書いてみた.

C 言語の float は IEEE 754 準拠だと明記されていないのですが,基本的には IEEE 754 形式だと思っていいはずなので,IEEE 754 基準で調べたら OK です.

IEEE 754 では,32bit の 2 進数で小数を表現するために,内部を「符号,指数部,仮数部」に分けています.それぞれが「1bit, 8bit, 23bit」です.

基本的に IEEE 754 - Wikipedia などを読めば分かるのですが,理解の確認のために再整理.詳しいことはパタヘネ辺りを読めばいいと思います.後で参照して補足します.

2進数は,小数点でどうやって表現されているか

浮動小数点 と 固定小数点 の2通りがありますが,ここでは浮動小数点のみを扱います.なお,固定小数点は,ある桁に小数点があるものと見なす(例えば,256 倍しておく)ものです.

32bit の 浮動小数点数 は,基本的には,以下の数式で表現できます( ^ は累乗).この形式で表現できるのは正規化数です.例外は後述.

(-1) ^ (符号) * (1.仮数部) * 2 ^ (指数部-127)

符号部

これは単純に 0 なら 正,1 なら 負 です.整数の 2 の補数表現とあわされています.

仮数部

小数を IEEE 754 形式に表現し直す際に, 1.XXXX * 2^exp という形に直します.これを正規化といいます.仮数部には 1. の下の小数部である XXXX のみを持ちます.

「浮動小数点数 - Wikipedia」 の例http://ja.wikipedia.org/wiki/%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%95%B0#IEEE_754_.E3.81.A7.E8.A1.A8.E7.8F.BE.E3.81.99.E3.82.8B.E3.81.BE.E3.81.A7.E3.81.AE.E9.81.8E.E7.A8.8Bは説明がわかりにくいですが,2.5 であれば(十進数を xxx (10),二進数を xxx (2) と表すこととすると),

2.5 (10) = 10.1 (2) * 2^0 = 1.01 (2) * 2^1

と正規化され 0.25 (10) = 0.01 (2) となりますので,仮数部は 01 となります.残りの 21 bit は 0 で埋めます.

指数部

指数部は 「指数 + 127」 の値を格納します.なぜ,2 の補数を使わないかというと,(正規化数の)浮動小数点数の大小比較を簡単にするためです(混乱中ですが,たぶん後述).すなわち,8bit の 0 〜 255 で -127〜128 を表現します.先ほどと同様に,Wikipedia の例をパクってくると, 2^1 は指数部に 128 として表現されます.

よって,2.5 (10) = (-1)^0 * 1.01(2) * 2^1 は 0_1000,0000_0100,0000,0000,0000,0000,000 として,表現されます(コンマは手前から 4 桁区切りでつけているだけです).

irb で確認

packテンプレート文字列 - Rubyリファレンスマニュアル」によると,IEEE 754 準拠な環境なら簡単に変換結果を確認できるようです.

> [2.5].pack("g").unpack("B*")[0][0,32]
=> "01000000001000000000000000000000"
# 符号
> [2.5].pack("g").unpack("B*")[0][0,1]
=> "0"
# 指数部
> [2.5].pack("g").unpack("B*")[0][1,8]
=> "10000000"
# 仮数部
> [2.5].pack("g").unpack("B*")[0][9,23]
=> "01000000000000000000000"

確かにうまくいっています.

16777216.0, 16777217.0, 16777215.0 はどうなるのか?

16777216.0 (10) = 1.0 (2) * 2^24 ですので,符号は 0,指数部は 24+127,仮数部は 0 となりますね.

一方,16777217.0 (10) = (1.0 + 2^(-24) ) (2) * 2^24 ですので,2^(-24) を表現するには仮数部が 1 bit 足りず(23bit では 2^(-1) 〜 2^(-23) まで),丸められることとなります.

16777218.0 (10) だと (1.0 + 2^(-23) ) (2) * 2^24 ですので,23bit にぎりぎり収まるため,float で表現可能になります.

irb で確認してみると,確かに,16777216.0 == 16777217.0 != 16777218.0 となっていますね.

> [16777216].pack("g").unpack("B*")[0][0,32] # 仮数部は 00000000000000000000000
=> "01001011100000000000000000000000"
> [16777217].pack("g").unpack("B*")[0][0,32] # 仮数部は 00000000000000000000000
=> "01001011100000000000000000000000"
> [16777218].pack("g").unpack("B*")[0][0,32] # 仮数部は 00000000000000000000001
=> "01001011100000000000000000000001"

.double だと,仮数部の bit 数が増えるので,今回の数は全て表現可能です.

16777215.0 になると,今度は指数部が 1 小さくなりますので,仮数部において 1.0 が 2^(-23) * 2^23 と表現できるようになり,丸めが発生しません.

# 1 違いが大きな違いに
>  [16777215].pack("g").unpack("B*")[0][0,32]
=> "01001011011111111111111111111111"
>  [16777216].pack("g").unpack("B*")[0][0,32]
=> "01001011100000000000000000000000"
# 16777215 と 16777216 との指数部の比較をしてみると,1 異なる
>  [16777215].pack("g").unpack("B*")[0][1,8]
=> "10010110"
>  [16777216].pack("g").unpack("B*")[0][1,8]
=> "10010111"

0.1 について

0.1 というのは,2進数の浮動小数点表記において,正確に表現することができないかずです.直感的には,そんな馬鹿な!と言いそうになるのですが, 2^n をどう足し合わせても 0.1 ちょっきりにはなりません(0.1 = 1 / 2 * 1 / 5 ですが,5 は素数のため,1/5 は m/2^n では表すことができません).

では 0.1 がどう表現されるかというと,正規化すると 16 倍して 1 を超えるので,指数部は -4 となり

0.1 * 16 (10) = 1.6 * 2^(-4) (10)

仮数部は 0.6 ≒ 1/2 + 1/16 + 1/32 + ... (= 0.5 + 0.0625 + 0.03125 + ...) であり,実際に irb で確認してみると(厳密には 0.1 0110 0110 0110 ... と 0110 が繰り返す循環小数となるはずです)

> [0.1].pack("g").unpack("B*")[0][0,1]
=> "0"
> [0.1].pack("g").unpack("B*")[0][1,8]
=> "01111011"
> [0.1].pack("g").unpack("B*")[0][9,23]
=> "10011001100110011001101"

こちらは,bit 数不足の問題ではないので,double でも回避できない本質的な表現能力の問題です.3進数では正確に表現できる 1/3 を 10進数 では循環小数としてしか表現できないのと同じことです.

後,たぶん,一般にループの終端条件に小数を用いる場合は許容誤差込みで大小判定します.while (f != 10.0) ではなく while (10.0 - error <= f && f <= 10.0 + error) のようにするのではないかと思います.たぶんね.

非正規化数について

余力が有れば追記.

大小比較について(整理中)

というのも,正規化されていれば, (-1)^符号 * 1.仮数部 * 2^(指数部+127) と表現されますので,「符号,指数部,仮数部」と並べておくことで,大小比較が簡単になるはずです.

例えば,lhs と rhs の大小を比べる際には,

lhs, rhs の双方が正

  1. どちらかの指数部が大きい → 指数部の大きい数が大きい(∵正規化されているので)
  2. 指数部が等しい → 仮数部のより大きい数が大きい

これは,正の整数同士の比較において,上位桁が大きいほど大きいということで正しく判断できる.

lhs, rhs のいずれかが負

  1. 2の補数表現では最上位ビットが 1 だと負であり,「正の数 > 負の数」として正しく判断できる.

lhs, rhs の双方が負

  1. どちらかの指数部が大きい → 指数部の大きい数が小さい
  2. 指数部が等しい → 仮数部のより大きい数が大きい

こちらは 2 の補数表現同士の比較と一致しない・・・でいいんだっけ?