[back]

【雑記】
2009/5/20

何だかRPGとか延々やっていると、妙な苛立ちがあって精神的に宜しくない、まぁそれなりに面白いからやっているのだが、それでも浪費する時間を考えると何とも漠然とした苛立ちが湧き上がってくる. まぁ今週は少しバタバタしていて忙しいので、来週辺りは少々対処を考えた方が良さそうではある.

ここ数日扱っていた要素doubleの分数ライブラリ、桁あふれの対策や演算オーバーフロー時に通常のdouble演算に切り替える等の小細工を加え取り合えずはほぼ安定、所謂BCD系のライブラリと比較するとメリットは

  • 有限桁の日常計算程度の反復では誤差が発生し難く、BCDの場合に問題となる循環小数なども正確に処理できる為、ともするとBCD以上に直感的な計算結果を返す事ができる.
  • 内部的にdoubleであり入出力の想定桁数もdoubleそのままの特性を想定しており、また無理数などはそのままdouble型として表現する為、既存の浮動小数点数ライブラリと併用した時に比較的扱い易い.

デメリットとしては

  • 既約分数化でgcdを算出している個所や浮動小数点数を有理数近似で表現可能かを調べる反復計算などが含まれており、BCDと比較してもかなり処理が重い.
  • 加算・減算の反復処理に弱くこれらの累積では分子・分母が比較的大きな値になる為、プログラム的なループ処理などに扱うには不向き.
  • 演算による誤差の累積は免れるが内部的にdoubleである為最終的にdouble値として抽出する限り2進化誤差の影響は免れない.
  • 桁あふれなどは可能な限りの考慮はしているが、演算可能な範囲を超えた場合はdouble型に以降するので、常に全域で連続な結果を返すものでは無く、その「境界」が丁度露呈するようなケースでの挙動は非常に分かり辛いものとなる.

といった所か、まぁ特にwin32apiのBCD (OLEのdecimal系API) などでは全有効桁数が相対表現の上、循環小数などの丸めについて勝手にbankers roundで機能してしまう点なども頭の痛い所ではあるので、エンドユーザーサイドに見せる「数」の概念としてはこちらの方が妥当かもしれない、まぁとは言っても「数」のライブラリというのは細心の注意を払って余りあるものであるので、これを仕事などで扱う予定は無くあくまでプライベートなもの. 精度を完全に保証できるだけの自信はまだ無いし、ここ暫く書いている数と計算誤差の概念はプログラマでも正確な理解をしていない割合の方が極めて多い話 (自分の経験上でしか無いが、この話題を正確な理解としてまともな会話のできるプログラマというのは本当にごく僅かしか見かけた経験は無い(※1) なので、実際開発が自分自身では無く他人の立場であれば、外部の1プログラマが作った演算ライブラリなど余程こなれていない限りはまず信頼しないだろうという所 :-P

まー暫くは使い所を見極めながらぼちぼち影響の少ない個所で様子見というカンジ. なお上の話はあくまでエンドユーザーサイドに見せる「数」の概念に関するものに限定すべきで、実際には上記のような問題が顕著なのは非連続関数的な境界付近の挙動 (剰余や四捨五入、等値比較等) のみである為、コストなどを考えるとプログラムの内部的な反復計算アルゴリズムでは、やはり通常のdoubleで演算を行い、計算の性質により相対有効精度n桁程度 (0比較のみ絶対精度) を期待してその誤差を許容する関数を適用する方が妥当.

※1) 余談だが、ネット上のこの手の誤差の議論を眺めているとしばしば「文字列出力したものを取り込んで」みたいな話があるのだが、結局それって出力フォーマットの表示桁数n桁とした場合に相対桁数n桁で丸めるのと同じ話なのだが、、、無論2進化誤差など全ての誤差がこれで解消されるものでも無いし、使用するライブラリによっては文字列化で有効桁数の指定が無いものがあったり、Cのprintfなどの場合更に書式による丸めの挙動は何も規定されていなかったりする、これを表示と合わせてユーザーインターフェイスとして表示されている数値がそのまま使われるというのは (かなり精度を犠牲にするが) 一つの見せ方として (ユーザーにも分かり易い点で) アリではあると思うが、得てして掲示板などで前後の流れを見ると、回答している側もその辺までちゃんと理解して書いているようには思えないのだが、、、まぁ突っ込んでも疲れるだけなのでそういった公の場では敢えて指摘する事も無いのだけど、何だか見てて非常に疲れた気分になったり (まー何か色々あって最近はプログラマとして他人に期待する事もついぞ無くなったよなーみたいな、たまーに面白い人が偶然いればそれでいーじゃんみたいな、まぁともするとこういう思いは慢心による停滞にも繋がるし、まだまだ僕自身も純粋に技術だけ見てもロクな物じゃ無ぇみたいな所で、余り厭世的になるのもどーかとは思うのだけど、みたいな個人的なオチに落としておく(笑)

---------------

余談だけど、誤差の話は何もコンピュータの浮動小数点数特有の話でも無い、ただ結局の所浮動小数点数は数というよりはむしろ目盛りのついた定規のようなもので、例えば現実にも通常の1mm刻みの定規で測って10.5cm前後の数値を100個加算した結果には1mm程度x100の誤差が含まれる、よってこれに対し数10mmの正確さに左右されるような計算は全く意味を持たない. また同様にa*(b+c)のような演算においてb=1000.0, c=0.252などという値ではcの精度はbに畳み込まれてしまう(分かり易く値を大きく異なるもので表現したが入力の有効桁数が違うものについてはいずれも同様) 或いは100cm近傍の規格品について1/10まで目盛りを読んでも100.52cm-100.30cmみたいな計算が精度的にはほぼ1桁程度の意味しか持たないのも同様.

コンピュータによる計算は確かに随分と物事を楽にしたけど、ともすると上のような話を覆い隠してしまうモノかもしれない、実際に考えれば上のような馬鹿な集計はしないが、一旦Excelなどの数値に落とされてしまうとそれが見え難くなってしまう、みたいな. あくまで他人の話ではあるが、コンピュータが普及するようになってから会社の研究部門が出してくる数値の有効桁数や混入する想定誤差率が滅茶苦茶な資料が平気で出てくるようになったなどと愚痴られた事があったり(苦笑)

まぁそれ以前の問題として内部検討用の分析・研究資料をパワーポイントで (見栄えは良いが概要だけしか書いてない資料で) 作ってくるなどといった話もあって、その度に怒鳴りつける事になったみたいな話もあって、コンピュータの普及も良い事ばかりでは無いのかなぁなどと思ってみたり.

 

2009/5/18 VC7と浮動小数点数の最適化

分数ライブラリ (要素はdouble) の精度テストを走らせていた所、本来発生する筈の無い個所で誤差が発生・累積していて悩む羽目に、生成されたアセンブラコードで確認すると、VC7 (2003Toolkit版とDDK付属のversionで確認) で最適化を行った場合に、分数の既約化 (相互のgcdで除算(fdiv)を行う個所) が最適化の結果逆数 1/gcd の乗算(fmul)に変換されていた、表現桁の都合から__int64で求めたものをdoubleにしているのだが、gcdは整数であり、被除数もdouble型で正確に表現出来る整数であるので、除算結果は整数になる事を期待している、ここが逆数になる事で微小な誤差が混入していた模様. 回避用の丸めコードを加えた場合と-Opコンパイルオプションを比較した所、-Opオプションの方が全体の効率が良かったので、こちらを使う事に (問題になるのは部分的なコードのみなので実際にはpragma optimize("p", on)にて指定). まーそれだけの事なのだが、-Opオプションって初めて使ったなぁというカンジで、そういう事もあるというメモがてら ;-)

なおVC6では最適化ONでもfdivで実行されるので上記の問題は発生しなかった. VS2003のVC7は関連付け設定がいじられるのと、今となっては役にも立たない.NET 1.1の開発環境が入るのが嫌で入れていない為不明、またVS2005以降は通常の最適化が悪化しているのか、ランタイムのデザインに変更があったのかANSI版のライブラリを使用したプログラムでは軒並み (VC7はおろかVC6よりも) パフォーマンスが悪化してくれた (最悪のパターンでは1.5倍近く遅くなった) ので使ってない (今の所簡単なものから上は10万行程度のソフトまで10本程度比較、実行環境も2000とXPのみのテストでそれ程深くは追っていないが) 後はstrsafe使えというコンパイル警告がウザいというのも有り:-< いずれもANSI版のみでUnicode版ランタイムを使用した場合については不明. ちなみにPen4ではfmulはfdivに比べ5倍程度早いそーな、それよりも最近は浮動小数点数の除算よりも整数除算の方が遅い(他の要因もあるが純粋なスループットでは)というのが少々驚きだったり.

それ以外にもVC7について少々気になるのは複素数ライブラリの log(-4)の虚数部の解が安定しない事、複素数の対数関数は周期2piの周期関数になるので解が複数あるのは良いのだが、一般的には主値として-pi<x<=piの範囲を返すと期待したい所、C++の規格でどう決まっているかは確認していないが、ここの係数が-4をそのまま入れた場合と4に-1をかけて作ったものを与えた場合などの違いで、係数が+-piのいずれになるかが非常に不安定という挙動は規格以前の問題として気になる所. これもVC6では確認できなかったので、上記のような最適化の結果発生しているものなのか少々不安、log関数の実体はライブラリに入っているので-Opオプション付けても意味無いし、うーん :-<

結局現在使っている複素数の計算部分は半分位は自前のライブラリになってしまっているワケで X-<

# おまけのVC7メモ、浮動小数演算の例外は_control87などでマスクしてもSSEコードを使用する設定でコンパイルした場合は発生しないケースがあり、FPUフラグの設定以外にSIMDの設定もインラインアセンブラで変更してやる必要があるそーな、ちなみにVS2005ではこの辺の整合性はちゃんと取られるようになっているとか、まーそんな話もある模様.

 

2009/5/17 だらけ中

えー白状しますとPSPのティル・ナ・ノーグがやたら面白くて(※1)ここ1週間程進展なしです、かなり時間の無駄のような気がしながらも、取り合えず一回クリアするまではもう暫くはそんな具合かも.

そんな具合でがっつり取り組んでいないので、軽い内容という事で、以前の有理数近似のルーチンを使った分数計算のルーチンを組んでいたり (確かに日常計算的な用途では幾つかの誤差は軽減できるのだけど、まだ極限付近の挙動がちと不安、簡単な式インタプリタを書いて暫く挙動チェックの予定) 何故か数学の勉強(複素数関連) から派生して電気回路の勉強していたり (と言っても一般常識的な部分を押さえる程度で、それを使えるようになるまでやるつもりは無いですが(^^;; ※2) リッチエディットコントロールの挙動検証していて、結構いい加減かつ信頼できない作りで、結局色付き出力用のコントロール以上のものとして深入りするものでは無く、ある程度の重要度を持ったGUIパーツとして扱う場合はやはり自前でエディタコンポーネントを作る方が中長期的なリスクは遥かに低いという結論に落ち着いて (案の定と言えば案の定なのだが) がっかりしてみたり、まー色々.

※1) 間違って買ってしまう人がいないように一応補足しておくと、決して出来の良いものでは無いです、一昔前のフロッピーのゲームみたいに延々ロードが入るし、インターフェイスは使い辛いし、ゲーム自体のテンポもバランスも悪いし、見た目も内容も古臭いしというシロモノです、ええ. まぁ今のゲームより昔のwizardryとかrogueみたいな古いタイプのゲームの方が好きなら楽しめるかもしれませんが、決して万人に勧められるものでは無いです ;-)

※2) どの位が最低限の一般常識の基準かというのは難しいけど、例えるなら割とメーカー系なんかによく居るタイプのダメSEのプログラムに対する理解度と同程度位はという所でしょうか :-P

 

2009/5/4

電卓遊び、延々オンラインでDLできる関数電卓やポケコンのマニュアルに目を通す日々. ふと思い立ち所謂数値に付ける「単位」を実装してみた、ついでに単位付き数字を文法上複数結合可能にしてみるとこんな具合に.

、、、プログラマの感覚としては限りなくキモい(笑) ちなみに単位は別ファイルとして実際には関数呼び出しに変換されるので、使う計算によって単位を切り替える事が可能. 例えば熱力学の温度の基本単位はK (ケルビン、分子の(0点振動などを除く)完全な古典熱力学上の熱的停止状態である絶対0度を基準とする温度の単位) 以外は却下だが、そうは言っても日常的には℃などを使うワケで、その辺に対応する為の処置.

これは電卓だが文法的に衝突は無いので実は言語処理系にも同様のものが組み込める、ちなみに自前の言語処理系は (実際には使っていないが) 酔狂から2バイト文字は全てシンボルとして扱えるようになっている. この機能と上の単位を組み合わせた場合の想定ソースコードを書いてみると、、、想像を絶する位キモい代物に. 余りのキモさに悶絶しつつ 「流石にこれは無いなー(笑)」 としたが (せいぜい極めて限定的なDSLにおいて数値リテラルのSI単位系における接頭字をサポートする程度が最大限の譲歩許容範囲)、、、最大の問題は上の想定ソースコードが実際には (当然もの凄く格好悪いが) 思いのほか非常に分かり易かった(※1)事 orz 例えるならアイドルの写真を見てかわいい、と言ったら実はオカマだった とか、すぐそこの自販機にちょっと買い物に行く時に部屋着のジャージ姿で行くか、みたいな話と同種のやましさと気まずい感があるのは事実.

更に強い型付けの言語ならこういった単位をデータの型(例えば金額や回数)に適応し、コンパイル時の制約条件にすれば、間違って金額に商品の個数を代入するようなコードは完全に防げる、レイアウトの高さと幅を別扱いにするアプリでは間違って縦表現に使われているものを横表現の変数に指定していれば一目でバグだと認識できる、つまりちゃんとした意味でのアプリケーションハンガリアン (以前のMSスタイルの拘束的で最低なハンガリアンとは別物) を実践できる事になる、なるにはなるのだが、、、orz

 

※1) 実際には日本語シンボルについては過去の経験から、一般的なプログラマの常識から見ると非常にカッコ悪いながらも、コードの可読性やメンテナンス性については一定の評価をするものの (Cobolを誉める(※2)のと同じようなやましさはあるが、実際非常に内部が複雑なものだと見易いんだこれが) よくある「日本語プログラミング言語」については否定的、あくまで変数などの「記号」としての見易さは認めるものの、全てを日本語で記述するのは、言語の曖昧さをコンピュータが適切に解消し、また意図しない解釈がなされた場合に適切なフィードバックを提示できない限りは、むしろ日本語の曖昧さを過分に含む特性からもマイナスにしか働かない (語彙に全く英語はおろかアルファベットすら無い小学生などを対象にした入門的目的を除く) と感じている為、またどうしても (余り好きな言葉では無いが) 理系あがりの為、必要以上の冗長な構文は大嫌いという背景もある(※3)

※2) 実際BCD演算の詳細な桁数まで含めたコントロールと、固定ピッチ出力におけるレイアウトの簡易さについては非常に良くできていると思う(出力レイアウトは他の言語でもライブラリでほぼ補えるが、精度指定についてはプリミティブしてそれが完全な一貫性を持って言語に統合されている事に意味があり、単純な演算子のオーバーロードのような機能だけでは補うのは難しい) あくまで極めて限定的な用途に対する効果であるし、発狂しそうな冗長な構文と幾つかの言語機能としての不備は、それらメリットを全て打ち消て余りある程に最悪のものではあるが.

※3) 一つの意味論に対し2つ以上のキーワードトークンが付くのは自分の美的感覚としては極めて耐え難いものがある、例えばforeachはアリだがfor eachと書くのは、断じてそうあってはならないとすら感じる. そういった意味ではPythonや次期JavaScriptに提言されているリスト内包表記ですら (元の関数型言語に比べ意味論として) 冗長だと感じるし、C#のlinq構文などは実に醜悪に映る (「幸い?」な事に.NET3.0以降はXPでないと動かない為、現状ではまだ2000は切り捨てる事は難しく、今暫くは僕がこれを真剣に使う羽目になる事は無いだろうが:-P) 無論SQLやVisualBasicの文法などは論外だ (あくまで主観、ね;-)

 



過去の雑記
2009年 4月
2009年 3月
2009年 2月
2009年 1月
2008年 12月
2008年 11月
2008年 10月
2008年 9月
2008年 8月
2008年 7月
2008年 6月
2008年 5月
2008年 4月
2008年 3月
2008年 2月
2008年 1月
2007年 8月〜12月
2007年 7月
2007年 6月
2007年 5月
2007年 4月の雑記はありません.
2007年 3月
2007年 2月
2007年 1月
2006年 12月
2006年 11月
2006年 10月
2006年 4月〜9月の雑記はありません.
2006年 3月
2006年 2月
2006年 1月
2005年 12月
2005年 11月
2005年 10月
2005年 9月
2005年 8月
2005年 7月
2005年 6月
2005年 5月
2005年 4月
2005年 3月
2005年 2月
2005年 1月
2004年度


メールアドレス収集ロボット対策の為メールアドレスはHP上に記載しておりません、
ソフト内のドキュメントには記載しておりますので、御用の方はそちらまでお願いします.
since 2003/10/04, Y.Ume/Tabo