2012/05/30

NetBSD PR lib/46433 についてのコメント

外野がいきなりツッコミ入れるのもどうかと思うので、ここで。

この問題は、 m68k FPE のデバッグをしている時に、libm の exp() のテストがおかしいんじゃないかという疑問を持ったことに端を発する。

2012/05 時点で、m68k FPE の exp(x) が stub 実装で、常に x を返すという痛々しい事実はまず忘れておいて、そもそもこのテストコードの意味を考えてみる。



テストとは、
「信頼されたもの」を使って、「信頼出来るかわからないもの」が信頼出来るかどうか調べる行為である。

今回問題になってるテストコードは
exp(x + y) - exp(x) * exp(y) < eps

さてここで、「信頼されていないもの=調べたいもの」には .N をつけてみよう。

exp.N(x + y) - exp.N(x) * exp.N(y) < eps

左辺に信頼されていないものを集めて、右辺に信頼出来るものを集める。が、もうこれ以上移項できない。

そうするとこの式を見て分かるように、このテストコードでは、「左辺の式が eps 以下である」ことしかテストできていない。exp 自体が信頼できるかどうかは、このコードでは分からない。

仮に exp 自体がすでに信用出来るものである、とすると、このテストコードがテストすることになるのは、数学領域の「exp(x+y) = exp(x)*exp(y)」という式が数学的に正しいかどうか、であって libm の exp ではない。

このテストコードを、まがりなりにも libm のテストとして成立するように書きなおすとしたら、

#define Ex (計算済みのexp(x)を定数にしたもの)
#define Ey (計算済みのexp(y)を定数にしたもの)
exp(x + y) -  Ex * Ey < eps

とすれば、
exp.N(x + y) < eps + Ex * Ey

となって、「exp(x + y) が信頼出来るかどうか」のテストコードとして成立する。

もちろんこうなると、信頼されている Ex * Ey は事前に計算してよいので、

#define Exy (計算済みの exp(x) * exp(y) を定数にしたもの)
exp.N(x + y) - Exy < eps

としてよい。

また、x+y も信頼されているので事前に計算してよい。z=x+y とおけば、

exp.N(z) - Ez < eps

となる。すでにこれは exp[2f]?_product のテストではない。掛け算どこにも出てこない。

以上、libm のテスト exp[2f]?_product  は意味が無い、という考察でした。






もしかして、数学の正しさをテストしたかったんならごめん、ライブラリのテストコードじゃなくて他所でやって・・・

2012/05/18

IDispose 実装のパターン

忘れやすいので書き残しておく。

class Foo: IDisposable
{
 // アンマネージリソース
 private IntPtr unmanaged;

 // IDisposable を実装している他のクラス(このクラスがオーナー)
 private OtherDisposableClass other;

 // イベントを持ってて、このクラスがイベントをサブスクライブしてる
 // このクラスは参照してるだけ
 private ReferencedWithEvent refwe;

 // 自分のイベント
 public event EventHandler AnyEvent;

 // もし、アンマネージリソースをこのクラスが直接管理していなければ、
 // ファイナライザを用意しなくていい。
 ~Foo()
 {
  Dispose(false);
 }

 public void Dispose()
 {
  Dispose(true);
  GC.SupressFinalize(this);
 }

 protected virtual void Dispose(bool disposing)
 {
  if (disposing) {
   // Dispose() から呼び出された時は、保持しているIDisposableメンバを
   // null チェックしてから Dispose() を呼び出して null にセットしておく。
   // 他の例にあるような disposed フラグは使わない。
   // その理由は、other のインスタンスが Open() などのように
   // コンストラクタ外で確保される場合でも同じパターンでコードを書くため。
   // また、null チェックして null 代入しておけば Dispose() が複数回コールされても大丈夫。
   if (other != null) {
    other.Dispose();
    other = null;
   }
   if (refwe != null) {
    // サブスクライブしたイベントを解除
    // More Effective C# 23
    // イベントハンドラの定義宣言は省略...
    refwe.Event -= refwe_Event;
    refwe = null;
   }
  }

  // 直接このクラスが管理しているアンマネージリソースの解放処理をここに書く。
  // 仮に other がアンマネージリソースを保持していることを知っていても、
  // ここで Dispose を呼び出してはいけない。
  // ここはファイナライザからの呼び出しでも実行される場所で、ファイナライザからの
  // 呼び出しである場合、other はすでにファイナライズされているかもしれない。
  // .Net の GC は参照カウントでなくルート探索で動作するので、自分が参照して
  // いるからといって、そのオブジェクトがファイナライズされていない保証はない。
  // したがって、ここでは他のオブジェクトを参照してはいけない。
  // http://msdn.microsoft.com/ja-jp/library/system.idisposable.dispose.aspx

  // もし、IntPtr.Zero も有効な値なのであれば、
  // 別のフラグを用意して、開放したかどうかを管理する。
  if (unmanaged != IntPtr.Zero) {
   UnmanagedResource.Free(unmanaged);
   unmanaged = IntPtr.Zero;
  }

  // 単なる null 代入でいいものはここに書く。
  AnyEvent = null;

  // ObjectDisposedException を実装したければ、ここでフラグ立てるとかする。

  // もし、このクラスが継承クラスなら、
  // base.Dispose(disposing);
 }
}

2012/05/02

OS X 10.7+XCode 4.3+wxWidgets2.8+cmake で XM6i をmakeしようとして挫折するまで

もともと 10.5 が入っていた mac mini (2007)。これがターゲット。
10.6 DVD を購入。Apple Store で。届くのは速くて、翌日着だった。素晴らしい。
10.6をアップグレードインストール。
...オマチクダサイ
ソフトウェアアップデートで 10.6.8 (だっけ)まで上げる。
10.7 を AppStore で購入しようとして、RAM が 2GB 要ると言われてダウンロードすらできない。
ソフマップまで行って 中古の RAM 1GB と新品RAM 2GB。もう DDR2 667なんて売ってないよ。
そして100円ショップで、スクレイパー2本購入。
ケースの爪を2本折りながら、RAM交換。
10.7を AppStore で購入しようとして、AppleIDの腐った規約に渋々合意。
認証通してダウンロード開始。4GB。
...オマチクダサイ
...
10.7 インストール開始。
...オマチクダサイ
...
XCode 4.3 をダウンロード。1.5GB....
...オマチクダサイ
MacPortsをダウンロードしてインストール。
従来入っていた XCode 3.x と競合。えー、アンインストールするとかしてくんないの。
XCode3.x を手作業でアンインストール。
$ port install cmake +universal
configure が、コンパイラが無いっていうエラーで落ちる。
XCode4.3 が ppc のサポートを打ち切ったのが原因と分かるまで3時間。
$ port install cmake
$ port install nasm
$ port install wxWidgets
こいつ、なかで +universal してて動かない。
$ port install wxWidgets-devel
なんか依存してる perl のコンパイルが出来ないって怒られて動かない。

で。詰んだ。

結論:もうしない。