Island Life

2013/12/29

2進小数の10進桁での丸め

5.015を小数点以下2桁のところで丸めたらいくつになるべきか、という話。 小数に2進浮動小数点数を使っている場合、5.015は正確に表現できず、 もっとも近い表現可能な値は5.015よりわずかに小さな値となる。 とすれば、丸めた結果は近い方である5.01になるべきだろうか、 それとも元の表記から考えられる5.02になるべきだろうか。

この問題には、唯一の正解はなさそうだ。 そもそも5.01もしくは5.02も2進浮動小数点数で正確に表現できないので、 結果も浮動小数点数で得るとすれば、これは「丸め」操作ではないのだ (2進で考えた場合、桁数は減っていない)。 「丸め」操作なら、「二重丸めはしてはいけない」という原則があるけれど、 そもそも丸めでないのでこの原則が適用できるかどうかも曖昧である。

ただ、モデルを定めれば、そのモデルでのあるべき解というのは考えられると思う。

以下、混乱を避けるために、正確な数を [5.015]と表記する。 一方、(NaN, 無限大を除く)2進浮動小数点数はそれぞれ正確な数値と対応しているけれど、 10進表記で書くと長大になるので、通常「曖昧さの無い範囲で最短の表現」が取られる。 それを{5.015}と書こう。どちらか解釈が確定してない場合は普通に5.015と書く。

つまり{5.015}というのは[5.015]にもっとも近い2進浮動小数点数で、 倍精度であればその正確な値は [5646388032815759/1125899906842624] である。 (この有理数は、倍精度浮動小数点数の定義から計算できる。Gaucheの場合、 0.9.3.3以前であれば (inexact->exact 5.015)、 現在の開発版であれば (real->rational 5.015 0 0 #f) とする。)

ではいくつかモデルを考えてみよう。

1. 浮動小数点数は、その2進数値が表現する正確な値に対応していると考えるモデル

5.015と言っている数は厳密に {5.015} = [5646388032815759/1125899906842624] を示している、 もしくは{5.015}を代表値として±ε/2の誤差を含んでいる、と考える立場。 数値計算ではこっちが普通だと思う。

  • 1a. {5.015}[5.015] より少し小さい。 従って[5.02]ではなく[5.01]に丸めるべき、と考える。
    [5.01]も2進浮動小数点数で正確には表現できないので、 もっとも近い浮動小数点数 {5.01} を答えとして採用する。 これはdoubleなら[2820379266640773/562949953421312]に等しく、 [5.01]より少し小さい。
  • 1b. 「近い方へ丸める」には近さを判定しなければならないが、[5.01]{5.015} の距離は2進浮動小数点演算では正確に計算できない。 1a.の方法は、距離の判定で近似演算を行い、さらに結果を近似しているので、 二重丸めの臭いがする。
    そこで、比較演算に使う先もあらかじめ正確値を使ってみよう。 つまり、{5.015}{5.01}{5.02}をそれぞれ比べるのだ。
    gosh> (real->rational 5.01 0 0 #f)
    2820379266640773/562949953421312
    gosh> (real->rational 5.02 0 0 #f)
    1413004383087493/281474976710656
    gosh> (real->rational 5.015 0 0 #f)
    5646388032815759/1125899906842624
    gosh> (- 5646388032815759/1125899906842624 2820379266640773/562949953421312)
    5629499534213/1125899906842624
    gosh> (- 5646388032815759/1125899906842624 1413004383087493/281474976710656)
    -5629499534213/1125899906842624
    
    この通り、{5.015}{5.01}{5.02}のちょうど中間にある。 「偶数丸め」原則を結果の10進表記にあてはめて考えるなら、{5.02}が答えとして採用される。

2. 浮動小数点数は、その10進表記が本来表したかった数であって、正確に表現できない場合は便宜上もっとも近い値で近似している、とするモデル

つまり、5.015というのは[5.015]という意図なんだけど、 計算機では表現できないから仕方なく{5.015}を代わりに使ってる、と考える。

こちらは日常の感覚に近い。我々は10進表記を見たら、「その数字は真の値とは違う、仮の表記」 と考えるよりは、「その数字が真の値、計算機内部の表現が仮の表現」と考えるだろう。

ややこしいが、この違いは誤差を考慮しても現れる。下図において、5.015という表記を 見た時に日常的にとらえる感覚が上、計算機に適した解釈が下である。 (誤差分布をガウシアンみたいに書いたけど、多くの場合は一様分布の方がふさわしいかも)。

[image]

この場合、5.015は本来[5.015]なんだから、小数点数以下2桁で丸めたら 難しいことを言わずに結果の表記が5.02になって欲しい。(その5.02が内部で どう表現されるかは計算機が良きにはからえ)。

このモデルで計算する場合は、計算機内部で{5.015}[5.015]に 変換したうえで、10進数としての処理を行う必要がある。もちろん[5.015]は 2進浮動小数点数では表現できないので、例えば[5015/1000]として扱うのだ。

ちとややこしいのはこの変換が表記に左右されることで、 例えばもともとの数値が5.01534と表示されていたら人間は自然に[5.01534]である と認識するだろう (ユーザが有効数字をimplicitに想定するということ)。 なので計算機は「10進表記で最適な表示をした場合の桁数を算出して、それが表す 正確な数を求める」という操作をしないとならない。

この点では、「一度文字列にして操作する」のようなナイーブな実装が案外的を射ていたりする。

このモデルでは、日常的なアプリケーションでユーザの直感に反する振る舞いは出てこないだろう。

ただ、10進表記に直す時に一回近似が起きてて、そこからさらに丸めるってのが 二重丸めくさくて怪しい感じはする。

Gaucheで実装するとしたらどうしよう?

「10進表記の小数点以下何桁で丸める」というのは計算途中ではなく ほぼ常にユーザへの呈示の時に使われると思うので、 ユーザにとって混乱の少ない表記になるのが望ましいだろう。

しかし、Gaucheの浮動小数点数の扱いは原則として1.のモデルを取っている。 つまり浮動小数点数を正確に解釈する場合は、定義に従ってその示す値を使う、ということだ。 なのでここだけモデルを変えるのも気持ち悪い。

いやまてよ、そもそもこの操作は「10進表記に直す」時にしか問題にならないのだから、 double, int -> double であるような「10進n桁で丸める」関数を考えるのが間違いなのかもしれない。結果が文字列で得られれば良いのだから、 double, int -> stringという関数にすべき、つまり round関数のバリエーションとするのは誤りで (だってdoubleのドメインでは丸めじゃないもの)、number->stringのオプションとして実装すべきかも。

number->stringで桁数を指定するのは、Gaucheが使ってる Burger&Dybvigの論文にちゃんと誤差最小にする方法が出てるので、 素直にそれを実装するのが正解かな。

(追記2013/12/31 02:33:28 UTC):いやまてよ、Burger&Dybvig使って小数点以下2桁で打ちきると、{5.015}[5.01]に近いから誤差最小で5.01になっちゃうのかな? 要調査。 もしそうなら、必要に応じて1bのアルゴリズムを別途用意すべきかも。

過去の浮動小数点数に関する話題:

Tags: Programming, Gauche

2013/12/28

こういうのはおもしろい (差別についての続き)

人工知能学会の表紙の件について最尤推定とMAP推定したらがっかりした

抽象化でもこうやって定式化すると議論の土台になって良いですな。

フレームワークについては異議なし。議論すべきは点はふたつ。

  • この記事で論じられているように、前提条件を変えると結論が変わる。 前提条件の見積りをどうするか
  • 批判をするというのことの意味

まず前提条件について

パラメータの名前を「蔑視」にしていて、これはまあ議論の発端でそういう 言葉遣いがあったから仕方ないんだけど、差別のフレームワークを 論じる時にはちとまずい言葉である。「蔑視する」という行為には ネガティブな印象を持つ人が多いだろう。したがって人はかなり積極的な 理由が無ければ「私は××を蔑視している」と自認することはない。

差別の問題はそれが無意識で起きることで、つまり 「○○が××するのは常識だろ」「普通○○は××だよね」という、 あまりに当然すぎて普段思いつきもしないくらいの認識が根っこにある。 これは被差別側にもあてはまる。「予断でもって不利益を被っている」こと自体を 認識していなかったり、むしろそれを良いことと認識することさえある (極端なのが「奴隷の鎖自慢」というやつ)。

なので、上のエントリにあるように「女性なら<<女性差別的視点>>を持つ割合はかなり低いだろう」 というような見積りは自明ではない。

無意識の予断について興味があれば、例えば次のテストをやってみて欲しい。 自分が意識していない関連付けについて気づかせてくれるかもしれない。 トップページは英語だけど、"Project implicit social attitudes"で 日本語を選択すれば日本語のテストができる。登録する必要はない。 ただ、日本語だとテストの種類が少ないな… 英語だと今回の話題に関連する「ジェンダーとキャリア」のテストがあるんだけど。 ちなみに私は「男性とキャリア、女性と家庭を結びつける傾向がかなり強い」と出た。 やってみれば分かるが、考えて結果を操作できるようなものではない。 頭では対等と思ってても、身体は正直だな、ってやつだね。

私は、上のエントリ著者が「ありえない仮定」と言っている、平均70%くらいの人に バイアスが有る、くらいの方がむしろ現実を反映してると思う。 むしろもっと高いと思う。

何か統計情報があれば教えて欲しいけれど、実際の数字はどこまでを意味有るバイアスと 見なすかで変わってくるので、数字自体に絶対的な意味を持たせるのはまずい。それは 次のトピックと係わってくる。

なぜ批判が出るのか

とても重要な前提は、 差別についての批判は特定の人や行為の「善悪」を決めるものではないということ。

批判されて「○○したら悪いのかよ」という反応が見られるけど、いえ、悪くないです。 法律に触れていないなら、○○することは自由であります。

ポイントはそこではない。

差別問題というのは簡単に言えばこういうことである:

  • 「誰それは○○だから××だろう」という予断でもって、 ある集団が、その予断を受けない他の人々に比べ社会的に不利益を被ること

ここで○○は大きなグルーピング(性別とか、国籍とか、民族とか、年齢とか)で、 ××であるかどうかには他の要素の方が大きく影響するにもかかわらず、 それら他の要素を考慮することなく「○○だから××」と判断される場合を対象としている。

また、個々人の感情や判断は基本的にそれぞれの自由なので、 例えば個人商店のオーナーが「俺の親は××人にひどい目に遭わされたから ××人はお断りでぇ」とするのも自由ではある。それをひどいと思う人は 行かなければいいだけだから。もちろん批判するのも自由であるが、 その批判を受け入れるかどうかもまたオーナーの自由だ。

しかし、その観念が社会的にある程度遍在している時、 たとえばある地方でどの店も「××人お断り」となっている、という状況になると、 ××人は困ってしまう。

これは構造の問題だから、その構造を少しでも改善していきましょう、というのが 差別問題への対応なわけ。

誰か特定の人を断罪するものでもないし、 また誰か特定の人が「差別されて傷ついた!」と言ってるのに同情することでもない。

「これは女性蔑視だ!」という命題の真偽を決めるのは問題ではなくて、 現に生じている性役割の固定化による不利益を減らすのに何かできないか 考えようや、っていうのが出発点なわけだよ。

人間なんだから、何らかの予断を持って判断すること自体は避けがたいし、 予断を持つことが「悪いこと」ではない。

でも、気づいてない構造によって誰かが困ってるとして、「ああそうなのか、 じゃあ気をつけるよ」でそれが軽減されるなら、そうしない理由は無いんでないの?

もちろんその指摘が当たってないものであれば、「あなたの指摘は一般的には もっともだけど、今回のこの表現はちゃんと理由があってこうしてるんでこれで通すよ」 とか「あなたの論はちと極端すぎて、本来の目的にとって逆効果だよ」とかいうのもあり。

賛成でも反対でも、「不利益を生じる構造を減らす」という目的を忘れないように 議論するのが建設的だろう、ってことっすよ。

Tags: 生活, 社会

2013/12/27

サベツダー

人工知能学会誌の新しい表紙について、性差別の観点から批判が出てるという話について。

もう大人の対応である公式コメントが出ているので、 話としては収束してると思うんだけど:

人工知能学会誌の表紙、女性イラストレーターが描いていた

こうしたネット上の反応について、編集委員長の松尾准教授は、次のように話した。

「ネット上で広く議論をしていただくのは有り難いと思っています。学会としては、女性を差別したり蔑視する意図はありません。ただ、そういう意見もあるときちんと受け止めて、今後の表紙デザインを考える上で参考にしていきたいと思っています」

自分は最初の批判を見た時に性役割の文脈で順当な(想定される)批判だなあと思ったんだけど、 批判への反論やそのまた反論を見てると色んなレイヤでの議論が入り乱れてて カオスになってた。

まあどのレイヤで議論するかは自由なんだけれど(感情に感情で返すとかも)、 差別の文脈を踏まえてない意見はどうも的外れに見えてしまう。 わざと文脈を外して茶化してるようにも見えない意見も多くて、 基本的な「議論の枠組み」に結構隔たりがあるんじゃないかと感じた。

自然科学系とか工学系にいると、相対化して抽象する、という操作を良くやる。 「○○が××しているのを描くのは○○差別だ」という命題を見たら、○○や××を変数にして 色々なものを当てはめて不変条件を見つけるとか。 なので、「じゃあ描かれてるのが男だったら男性差別になるの?」といった反応になる。 また、表現者と表現内容を切り離して議論する、という習慣もある。 誰が言ったかではなく、あくまで言われた内容のみを材料として考える。 なので「この表現がダメなら△△にあるあの表現はどうなんだ」という例を持ち出したくなる。

差別といった社会的な問題は対照的に、「誰が」「何について」「どこで」「いつ」表現したか、 という文脈が極めて重要になる。

今回の話では、女性型を描くか男性型を描くか、は対称な話ではない。 なぜなら背景にある歴史やステレオタイプが非対称だから。 なので、描かれるものを入れ替えたらどうなのよ、とする議論は的外れ。 入れ替えたいなら文脈ごと置換可能なものを持ってこないとならないけど、 それはなかなか難しい。

これが学会誌というそれなりに公共性が高い(少なくとも、 学会はどこも性役割について中立であるべきコミュニティとされてると思う)ところに 出てるってのも重要で、 中立性を要求されないコミュニティがやるぶんには全く問題ではないし、 個人的な見解や嗜好を表明することとも別の話である。 (なので、これは表現の自由とは直交する話。ここ重要。 (追記2013/12/31 01:43:57 UTC)完全に独立でないので「直交」は不適切。言いたかったのは、今回の文脈上での表現の是非を議論することは、文脈を外した一般的な表現規制の是非の議論につながらない、ということ。コメント欄の議論参照。) 誰が言ったかが問題の重要な一部なので、「そう言うお前も差別してるだろ」という反論はやっぱり 的外れ。主語は入れ替え可能な変数ではないのだ。

という前提を踏まえて、自分なりにこの手の批判の論理をまとめるとこうなる。

  • ある固定観念 (それが現状の追認である場合も多い) があって、 それによって不利益を被っている集団がある。できれば不利益を減らしたい。
  • 既に固定化されている役割を無批判に描くことは、 多かれ少なかれ固定化の強化につながる。
  • その表現に必要性があるなら (例えば映画や小説などの表現で、現状をありのまま描写する必要がある場合) いいんだけど、選択の余地がある公共性の高い場所で、 わざわざ固定観念の強化につながる表現を選ばれるのは、困るのだ。

批判に対して反論するにしても、このロジックを押さえた上での議論じゃないと 話がすれ違っちゃう。 批判の目的は不利益の解消にあり、表現そのもの是非は二次的である、 というのもポイントで、不利益の解消を忘れて表現の是非だけ論じても意味がない。 (このロジックはまた、根拠ある批判なのか単なるヒステリックな表現刈りなのかを 判定するのにも使える。) 論点は、「そういう固定観念はあるのか」「どういう不利益があるのか」 「表現の必要性は」「公共性は」あたりになるだろう。

まあ、とはいっても固定観念というのは自分で気づけないから固定観念なんであって、 うっかりそれを言っちゃって批判を受けたら、「気づきませんでした、これから気をつけます」 っていうのが順当な対応で、人工知能学会はまさしくその通りの対応をしたわけで、 問題としてはもう収束してる。

自分としては、文脈を切り離す訓練を受けている人と文脈を重視する訓練を受けている人の すれちがいが際立つなあ、と思った事例だったので記しておく次第。

(追記2013/12/29 01:13:31 UTC)続き→こういうのはおもしろい

Tags: 生活, 社会

2013/12/26

10年

米国に来て、やっぱり芝居がやりたくなって演技のクラスをとりはじめ、 初めてオーディションを受けたのが2003年10月だったので、気がつけば 10年経ったことになる。役者で喰ってくのは無理だけれど、 副業として細々と「毎年、芝居か映像(映画, TV作品)の どちらか1本できたらいいな」と思ってやってきた。今年は芝居("All That Remains", KKT)と メジャーTV("Hawaii Five-0")に出られたのでかなり充実していたことになる (映画"Under the Blood Red Sun"も決まってるけど、撮影は来月に延びた)。

なんとなく、これまでやったプロジェクト(と、オーディションに落ちたプロジェクト) をグラフにしてみた。報酬が出る仕事も 大学の映画学科の学生映画もごっちゃにしてるので実績としての意味はあまりないけれど、 自分の挑戦の記録としては多少の意味があるかも。

[image]

年毎のばらつきがありすぎるけど、何となく上昇傾向ではあるので こんな調子でゆるゆるやって行けたら良いな。

Tag: 芝居

2013/12/24

無限多倍長整数の右シフト

Bignumには右論理シフトが無い、という記事

オーバーフローとシフト演算

おそらく、Javaの場合は最上位bitが符号bitになるんで、シフト対象がわかりますが、Rubyの場合は最上位bitがわかりません。 たぶん型という概念がないんで、最上位bitが32bit目なのか、64bit目なのがわからないんでしょう。

Javaのコードを移植する場合は右論理シフトも要注意です。

論理シフトが無いというより、区別の意味が無いと言った方がいいかなあ。

有限桁数で考えると「最上位bitの扱いの違い」が目につくんだけれど、 無限多倍長整数(2の補数表現)の場合、左には無限にビットが続いていると考える。 正の数なら0が、負の数なら1が無限に続いている。

  5  : ....0000101
 -5  : ....1111011

右シフトする時は単にそのいくらでも続いてるところから0や1が供給 されるだけなんで、算術とか論理とかの区別を持ち込む余地がないのだ。

与える数を有限の範囲でぶった切ってやれば、論理シフトの振る舞いが得られる。

  (define |2^32-1| (- (expt 2 32) 1))
  
  (ash -10 -1)  => -5                          ; -10 >> 1
  (ash (logand -10 |2^32-1|) -1) => 2147483643 ; -10 >>> 1

「左に無限に続いている」という振る舞いは、各種ビット演算で 確かめられる。

  (logbit? 100 -1) => #t  ; -1の100ビット目は1

なお、上の記事中のinteger overflowについては、0を中心としたmoduloが あれば一発である。R6RSのmod0がそのものずばり。

  (mod0 (+ 2147483647 1) (expt 2 32)) => -2147483648

Tag: Programming

More entries ...