プログラミング所感 - 前へ 目次次へ


06/01/06(金)

今年の予想など 。
2007年問題で、来年から3年ほど、大量の退職者が出る。多額の退職金が企業から個人へ流れる。 企業向けマーケットが冷え込み、個人向けマーケットが活況になり、インフレ傾向になるかもしれない。
医療、化粧品、旅行、金融、派遣などの景気が良くなるだろうか。今後、数年で、無線機器が飛躍的に伸びるような気がする。

プログラマのためのユーザインタフェースデザインが参考になる。

isbn:4492531947 ここが変だよ日本の管理職 を読んだ。定型作業をブレイクダウンして効率化し、 ホワイトカラーの生産性を上げようというものだ。 個人的には、自分の仕事は、弁護士のように不定形の部分が多いような気がする。 報酬としては、クライアントに付き合った時間給と経費と成功報酬になっていれば、よいような気がする。


06/01/07(土)

今日も通常の出社日 。
自作の乱数クラスをシリアライズしようとしたが、Randomをメンバに持っていて行き詰った。 そこで、RandomをMersenneTwisterに代えて、以下を追加した。http://takel.jp/mt/
/// <summary>複製</summary>
public object Clone()
{
	MersenneTwister r = new MersenneTwister();
	r.mti = mti;
	r.mt = (uint[])mt.Clone();
	return r;
}
/// <summary>文字列表現</summary>
public string Expression
{
	get {return ToString();}
	set
	{
		if (value.Length != 4+N*4*8/6) throw new ArgumentException();
		mti = short.Parse(value.Substring(0, 4), System.Globalization.NumberStyles.HexNumber);
		byte[] b = Convert.FromBase64String(value.Substring(4));
		for (int i=0;i<mt.Length;++i) mt[i] = BitConverter.ToUInt32(b, i*4);
	}
}
/// <summary>文字列化</summary>
public override string ToString()
{
	byte[] b = new byte[mt.Length*4];
	for (int i=0;i<mt.Length;++i) BitConverter.GetBytes(mt[i]).CopyTo(b, 4*i);
	return mti.ToString("x4") + Convert.ToBase64String(b);
}
Expression以外をXmlIgnoreにすれば、Xmlでシリアライズもできる。

06/01/10(火)

Tree用の データ構造を作ってみた。2時間ほどで作ったので、たたき台程度。
using System;
using System.Collections;
using System.Collections.Generic;

namespace CSTest
{
	/// <summary>ペア</summary>
	public struct Pair<T, U>
	{
		/// <summary>要素1</summary>
		public T First;
		/// <summary>要素2</summary>
		public U Second;
		/// <summary>コンストラクタ</summary>
		public Pair(T t) { First = t; Second = default(U); }
		/// <summary>コンストラクタ</summary>
		public Pair(T t, U u) { First = t; Second = u; }
		/// <summary>等値演算</summary>
		public override bool Equals(object obj)
		{
			Pair<T, U> pr = (Pair<T, U>)obj;
			return First.Equals(pr.First) && Second.Equals(pr.Second);
		}
		/// <summary>ハッシュコード</summary>
		public override int GetHashCode()
		{
			return First.GetHashCode() ^ Second.GetHashCode();
		}
		/// <summary>文字列化</summary>
		public override string ToString()
		{
			return First.ToString() + ", " + Second.ToString();
		}
	}
	/// <summary>Treeの要素</summary>
	public class TreeNode<T>
	{
		/// <summary>値</summary>
		public T Value;
		internal LinkedList<TreeNode<T>> _Nodes;
		/// <summary>子要素</summary>
		public LinkedList<TreeNode<T>> Nodes
		{
			get { return _Nodes; }
		}
		/// <summary>先頭</summary>
		public LinkedListNode<TreeNode<T>> First
		{
			get { return _Nodes.First; }
		}
		/// <summary>最後</summary>
		public LinkedListNode<TreeNode<T>> Last
		{
			get { return _Nodes.Last; }
		}
		/// <summary>子要素の数</summary>
		public int Count
		{
			get { return _Nodes.Count; }
		}
		/// <summary>コンストラクタ</summary>
		public TreeNode() : this(default(T)) { }
		/// <summary>コンストラクタ</summary>
		public TreeNode(T t) { Value = t; _Nodes = new LinkedList<TreeNode<T>>(); }
	}
	/// <summary>Tree</summary>
	public class Tree<T> : IEnumerable
	{
		private TreeNode<T> _Root;
		/// <summary>根</summary>
		public TreeNode<T> Root
		{
			get { return _Root; }
		}
		/// <summary>コンストラクタ</summary>
		public Tree()
		{
			_Root = new TreeNode<T>();
		}
		/// <summary>コンストラクタ</summary>
		public Tree(T t)
		{
			_Root = new TreeNode<T>(t);
		}
		/// <summary>追加</summary>
		public void Add(T t) { _Root._Nodes.AddLast(new TreeNode<T>(t)); }
		/// <summary>追加</summary>
		public void Add(LinkedListNode<TreeNode<T>> ln, T t) { ln.Value._Nodes.AddLast(new TreeNode<T>(t)); }
		/// <summary>削除</summary>
		public void Remove(LinkedListNode<TreeNode<T>> ln) { ln.List.Remove(ln); }
		internal IEnumerator GetEnumerator(int level, TreeNode<T> tn)
		{
			yield return new Pair<int, T>(level, tn.Value);
			LinkedListNode<TreeNode<T>> ln = tn.Nodes.First;
			while (ln != null)
			{
				IEnumerator en = GetEnumerator(level + 1, ln.Value);
				while (en.MoveNext()) yield return (Pair<int, T>)en.Current;
				ln = ln.Next;
			}
		}
		/// <summary>反復子</summary>
		public IEnumerator GetEnumerator() { return GetEnumerator(0, _Root); }
	}
	class Program
	{
		static void Main(string[] args)
		{
			Tree<int> t = new Tree<int>(123);
			t.Add(234);
			t.Add(t.Root.First, 345);
			t.Add(456);
			foreach (Pair<int, int> pr in t) // pr = (レベル, 値)
			{
				string s = pr.Second.ToString();
				Console.WriteLine(s.PadLeft((pr.First + 1) * 4));
			}
			// 出力
			//  123
			//     234
			//         345
			//     456
		}
	}
}

06/01/11(水)

ゲームを考えた 。
(1)将棋でネクストバッターズサークルを作る。取った駒は、一度、ネクストバッターズサークル に移動しなければ、打つことはできない。移動にも一手かかる。ネクストバッターズサークルには、n個までおける。 (2)将棋で取った駒は、自陣にしか打つことはできないものとする。 (3)時計盤と12面サイコロを使う。サイコロの目が出たら、そこに駒をおく。対角に並んだら勝ち。バックギャモンと同じくダブリングキューブを設ける。

06/01/13(金)

また、ゲーム 。
ルール
  • 6つの空のマスを用意し、自分からみて左から123456、相手から見ても左から123456と数字を振る。 (1つのマスの中の自分と相手の数字を足すと7になる)
  • ダブリングキューブを中央に置く。最初のビッドは1とする。
  • 交互にサイコロを振る。サイコロを振る前にダブルをかけられる。ダブルを受ける(Acceptする)とビッドは2倍になり、 ダブルを受けた方にキューブが行く。キューブのある方にしかダブルはかけられない。ダブルを断る(Rejectする)と ダブル前のビッドで負ける。
  • サイコロが1,2,3なら、自分の1,2,3のマスにコインを置く。既にコインがあれば勝ち。
  • サイコロが4,5,6なら、自分の4,5,6に相手のコインがあれば、取り除ける。
以下は、全48状態の勝率などを出力する。
class Test
{
	private static double Calc(double[,,,] dd, int k, int i, int j, int cc)
	{
		double d = 0;
		// 1 の場合
		if (i >= 1) d += 1;
		else d -= dd[k, j, i+1, cc];
		// 2 の場合
		if (i >= 2) d += 1;
		else d -= dd[k, j, i+1, cc];
		// 3 の場合
		if (i >= 3) d += 1;
		else d -= dd[k, j, i+1, cc];
		// 4 の場合
		d -= dd[k, j - (j >= 1 ? 1 : 0), i, cc];
		// 5 の場合
		d -= dd[k, j - (j >= 2 ? 1 : 0), i, cc];
		// 6 の場合
		d -= dd[k, j - (j >= 3 ? 1 : 0), i, cc];
		return d / 6;
	}
	[STAThread]
	static void Main(string[] args)
	{
		// 0 me, 1: center, 2:you
		double[,,,] dd = new double[2,4,4,3];
		int[,,] db = new int[4,4,3];
		dd[0,0,0,0] = dd[0,0,0,1] = dd[0,0,0,2] = 1;
		int k = 0;
		for (int cnt=0;cnt<1000;++cnt)
		{
			int knxt = 1-k;
			for (int i=0;i<4;++i)			// 自分
			{
				for (int j=0;j<4;++j)		// 相手
				{
					for (int c=0;c<3;++c)	// キューブ
					{
						// ダブルしない
						double d = Calc(dd, k, i, j, 2-c);
						db[i, j, c] = 0;
						if (c != 2) // ダブルする
						{
							double e = Math.Min(1, 2 * Calc(dd, k, i, j, 0));
							if (e > d)
							{
								db[i, j, c] = 1;
								d = e;
							}
						}
						dd[knxt, i, j, c] = d;
					}
				}
			}
			double f = 0;
			for (int i=0;i<4;++i)
				for (int j=0;j<4;++j)
					for (int c=0;c<3;++c)
						f += Math.Abs(dd[0, i, j, c] - dd[1, i, j, c]);
			if (f < 1e-14) break;
			k = knxt;
		}
		//using (StreamWriter sw = new StreamWriter("../../res.txt", false, Encoding.Default))
		{
			for (int i=0;i<4;++i)
				for (int j=0;j<4;++j)
					for (int c=0;c<3;++c)
						Console.WriteLine("Me {0} You {1} Cube {2} Double?={3} Accept?={4} Prob={5}", 
							i, j, c, db[i, j, c] == 0 ? 'N' : 'Y', dd[0, j, i, 2] > 0.5 ? 'N' : 'Y', dd[0, i, j, c]);
		}
	}
}
  • 先手の期待値は、0.142である。つまり、参加費を1個、最初のビッドを7個とすると、期待値は、-0.0056個となる。
  • コインの差が1個以上、または共に2個、または共に3個ならダブルする。
  • 差が2個以上、または自分が2個で相手が3個ならダブルを受けない。

06/01/23(月)

日経コンピュータより 。
PMOの調査によると、赤字プロジェクトの多くは、見積もりに問題があることがわかったそうだ。その結果、 PMOを設置している大手ITサービス会社50社のうち、28社は、PMOのチェックで受注を断ったことがある。 理由は、(1)要件があいまい、(2)見積もりと予算に大きな開き、(3)納期が短くスケジュールに無理がある。
(2)では、よほど別の理由がない限り、受注には無理があるが、(1)と(3)で受注するのは多いな。

06/01/31(火)

2プロジェクトで納品 。両方とも継続予定。さらに、新規が1本。提案が1本。12月に納品したやつは、3月に再リリース。

06/02/22(水)

納品終了しているのに、 いろいろ大変。

クラスMainFormの起動位置とサイズを覚える方法。
プロパティの設定で、MainFormLocationとMainFormSizeを作成し、初期値を入れておく。(型は、PointとSize)
MainFormのプロパティApplicationSettingsのPropertyBindingで、LocationをMainFormLocationにする。 コンストラクタの最後に、Size = (Size)Properties.Settings.Default["MainFormSize"];を追加。 MainForm_FormClosingで、
Properties.Settings.Default["MainFormSize"] = Size; Properties.Settings.Default.Save();
を追加。


06/02/23(木)

FILEポインタに 改行コードを送ると、バッファがフラッシュされると思っていた。 しかし、確認してみると、WindowsでもSolarisでもされない。

欲しいものが2つ。
1つは、議事録管理ツール(ProcTool)。

  • 作成時は、TreeMemo。
  • ProcToolには、TreeMemoからコピーペースト。内部はXML。行頭のマークで、タグを自動生成。
  • ProcToolで、ある程度編集可能なこと。内容をTreeで表示して、折りたたみできること。ProcToolからTreeMemoにコピーペーストも可能。
  • 1議事録を1ファイルで管理。複数ファイルをXPathで検索可能。よく使う検索はあらかじめ用意。(Aさんの参加した打合せの一覧など)
  • 顧客提出用には、HTMLを作成して渡す。画像はSVGで扱えること。
  • データベースは使わない。外部へのリンクも指定可能。ExcelやWordより、簡単に作成、編集、検索ができること。
もう1つは、要求仕様管理ツール。
  • しくみは、上記と同じ。内容は isbn:4774125237 に準じる。
  • トレーサビリティマトリックス(TM)に対応できること。
  • 見積もりに使えること。
InfoPathで、できるかはわからない。

06/02/28(火)

議事録管理ツールは、 結局、作ってしまった。いろいろバグっているかも。
http://plaza.harmonix.ne.jp/~fakira/turedure/ProcTool.zip

06/03/09(木)

VS2005のスタートキットの ムービーコレクションを手作業で作り直していると、表示がもっさりになってしまった。 具体的には、2枚のパネルを重ねて、表示/非表示を切り替えたときに、表示が遅い。 調べたら、パネルの背景画像の大きさに違いがあった。画像が大きいと遅い。LayoutはTileだから表示自体は変わらない。 HTMLの背景画像は、小さい方が遅かった気がするのだが。

06/03/16(木)

今回のOR学会は、 いつもより知り合いが少なかった。

C#では、派生クラスのインスタンス作成で、基底クラスのコンストラクタが呼ばれるとき、 thisは派生クラスになっている。C++ではならない。結構問題ではないだろうか。FxCopのCA2214でこれをチェックできる。 (エラーにしてもエラーにならなかったが)
.NET Expert#2がよい。isbn:4774126934


06/03/20(月)

講義で、VS.NETのスタートキットを 教えることにした。ちょっとした作業で、立派なUIが作成できるからだ。
しかし、スクリーンセーバーは日本語のRSSを指定するとうまくいかない。で、直した。
ムービーコレクションも、データベースを使わずに、アマゾンWebService(AWS)も使わないように直した。 AWSは、授業で教えるにはライセンスが厳しそうなので、代わりに「ぽすれん」にした。 難点は、インターネットに接続している必要があることだ。
http://plaza.harmonix.ne.jp/~fakira/turedure/StartMovieCollection.zip

06/03/23(木)

複数のプロジェクトで、 ごたごたしていたが、やっと落ち着いてきた気がする。

小学校は卒業式、5年以下の子供は休みのようだ。


06/03/28(火)

要求仕様書ツールも 作成。
http://plaza.harmonix.ne.jp/~fakira/turedure/RequestTool.zip

06/03/29(水)

社内でP2Pソフトが 使用禁止となった。BitTorrentも禁止だ。

06/04/01(土)

今日も出社日だが、 私と部長以外は、みんな帰ってしまった。
PSE法は、問題ありそうですね。 http://homepage3.nifty.com/koha_hp/SCNews/hpblock198/SCNews198.pdf

06/04/04(火)

トリプルディスパッチの例。
// Shape.cs
public abstract partial class Shape
{
  public static void Check(Shape sh1, Shape sh2, Shape sh3)
  {
    sh1.Check(sh2, sh3);
  }
  public abstract void Check(Shape sh1, Shape sh2);
  public void Show(Shape sh1, Shape sh2)
  {
    System.Console.WriteLine("{0} {1} {2}",
      GetType().Name, sh1.GetType().Name, sh2.GetType().Name);
  }
}

// Circle.cs
public abstract partial class Shape
{
  public abstract void Check(Circle sh1, Shape sh2);
  public abstract void Check(Circle sh1, Circle sh2);
}
public partial class Circle : Shape
{
  public override void Check(Shape sh1, Shape sh2) { sh1.Check(this, sh2); }
  public override void Check(Circle sh1, Shape sh2) {sh2.Check(sh1, this);}
  public override void Check(Circle sh1, Circle sh2) { Show(sh1, sh2); }
}

// Rect.cs
public abstract partial class Shape
{
  public abstract void Check(Rect sh1, Shape sh2);
  public abstract void Check(Rect sh1, Circle sh2);
  public abstract void Check(Rect sh1, Rect sh2);
}
public partial class Circle : Shape
{
  public override void Check(Rect sh1, Shape sh2) { sh2.Check(sh1, this); }
  public override void Check(Rect sh1, Circle sh2) { sh1.Check(this, sh2); }
  public override void Check(Rect sh1, Rect sh2) { sh1.Check(sh2, this); }
}
public partial class Rect : Shape
{
  public override void Check(Shape sh1, Shape sh2) { sh1.Check(this, sh2); }
  public override void Check(Circle sh1, Shape sh2) { sh2.Check(this, sh1); }
  public override void Check(Circle sh1, Circle sh2) { Show(sh1, sh2); }
  public override void Check(Rect sh1, Shape sh2) { sh2.Check(sh1, this); }
  public override void Check(Rect sh1, Circle sh2) { Show(sh1, sh2); }
  public override void Check(Rect sh1, Rect sh2) { Show(sh1, sh2); }
}

// Polygon.cs
public abstract partial class Shape
{
  public abstract void Check(Polygon sh1, Shape sh2);
  public abstract void Check(Polygon sh1, Circle sh2);
  public abstract void Check(Polygon sh1, Rect sh2);
  public abstract void Check(Polygon sh1, Polygon sh2);
}
public partial class Circle : Shape
{
  public override void Check(Polygon sh1, Shape sh2) { sh2.Check(sh1, this); }
  public override void Check(Polygon sh1, Circle sh2) { sh1.Check(this, sh2); }
  public override void Check(Polygon sh1, Rect sh2) { sh1.Check(sh2, this); }
  public override void Check(Polygon sh1, Polygon sh2) { sh1.Check(sh2, this); }
}
public partial class Rect : Shape
{
  public override void Check(Polygon sh1, Shape sh2) { sh2.Check(sh1, this); }
  public override void Check(Polygon sh1, Circle sh2) { sh1.Check(this, sh2); }
  public override void Check(Polygon sh1, Rect sh2) { sh1.Check(this, sh2); }
  public override void Check(Polygon sh1, Polygon sh2) { sh1.Check(sh2, this); }
}
public partial class Polygon : Shape
{
  public override void Check(Shape sh1, Shape sh2) { sh1.Check(this, sh2); }
  public override void Check(Circle sh1, Shape sh2) { sh2.Check(this, sh1); }
  public override void Check(Circle sh1, Circle sh2) { Show(sh1, sh2); }
  public override void Check(Rect sh1, Shape sh2) { sh2.Check(this, sh1); }
  public override void Check(Rect sh1, Circle sh2) { Show(sh1, sh2); }
  public override void Check(Rect sh1, Rect sh2) { Show(sh1, sh2); }
  public override void Check(Polygon sh1, Shape sh2) { sh2.Check(sh1, this); }
  public override void Check(Polygon sh1, Circle sh2) { Show(sh1, sh2); }
  public override void Check(Polygon sh1, Rect sh2) { Show(sh1, sh2); }
  public override void Check(Polygon sh1, Polygon sh2) { Show(sh1, sh2); }
}

// Program.cs
public class Test
{
  [STAThread]
  public static void Main(string[] args)
  {
    List<Shape> l = new List<Shape>();
    foreach (Type t in Assembly.GetExecutingAssembly().GetTypes())
      if (t.IsSubclassOf(typeof(Shape))) 
        l.Add((Shape)Activator.CreateInstance(t));
    foreach (Shape s1 in l)
      foreach (Shape s2 in l)
        foreach (Shape s3 in l)
          Shape.Check(s1, s2, s3);
  }
}
2次元オブジェクト(丸、四角、多角形)の衝突判定を考えてみよう。前にC++でダブルディスパッチの例を書いた。 C#でもトリプルディスパッチを上記のようにかける。特徴は、
  • 2次元オブジェクトの種類が増えても、partial classを活用しているため、 それまでの具象クラスのファイルは修正不要。
  • 2次元オブジェクトの種類が増えても、実行速度は不変。
  • ダブルでディスパッチでも、それ以上でも同様にかける。
  • Checkを再度呼び出す処理は、自動で生成可能。ただし、VS2005を使えば、書くのも簡単。

06/04/05(水)

VC++をはじめに 使ったとき、チュ−トリアルにお絵かきツールがあった。自分でお絵かきツールが作成できることに感動した記憶がある。 で、VS2005用に作ってみた。 http://plaza.harmonix.ne.jp/~fakira/turedure/PictureDraw.zip

06/04/06(木)

vectorでソフトウェア開発の 工程を勉強するツールとして、PSPStudyを公開しているが、VS2005用に作り直した(公開予定はなし)。 派生開発演習や規模見積もりや帳票作成は一切なくして、単純にプログラミング演習ツールとした。 特徴は、
  • テスティングフレームワークベースである。テストは全て事前に用意されていて、開発に専念できる。
  • テストが始めて通ると、私にメールが来るので、進捗がすぐわかる。
  • 模範解答は作成済みだが、提供はしない(PSPStudyではしていた)。
  • 課題は12題に増やした。従来の10題に、最短路と三角形の判定を追加。ソリューションのフォルダを追加するだけで、課題の追加も可能。
新人研修で使うつもり。

06/04/11(火)

C#1.0で作りためた、 数十のクラスをC#2.0用にしている。C#2.0の機能で簡単にできるところは、そのように作り直している。また、3部合同でC#2.0の勉強会もやる。

06/04/12(水)

シングルトン 。
/// <summary>[DP]シングルトン</summary>
public static class Singleton<T> where T : new()
{
	private static readonly T _Instance = new T();
	public static T Instance {get { return _Instance; } }
}
C#2.0だと簡単ですね。ダブルチェックロッキングはしてないけど、そんなに必要ないそうです。

06/04/13(木)

TableLayoutPanelの 子コントロールは、プロパティエディタ上でプロパティが増える。 例えば、子.ColumnSpan = 3; とできるように見える。 実際には、プロパティは増えず、親.SetColumnSpan(子,3);となる。 C#3.0のようだ。デザイン作成は楽になる。

06/04/21(金)

数学とコンピュータ数学の比較。
数学int, decimaldouble, float
任意の数字が対象有限桁数が対象有限有効桁数、有限指数が対象
数字以外は計算の対象外最大値、最小値を表せ、計算対象となる最大値、最小値、イプシロン、非数値、+無限大、-無限大を表せ、計算対象となる
数学のルールは成り立つ有効桁数内での数学のルールは成り立つ数学のルールで規定されない演算もでき、桁落ちなどにより、数学のルールが成り立たないこともある
0割は許されない0割は例外0割は矛盾しない計算
無限大は数字ではない無限大は表現できない無限大も計算対象なので、数字と同様に扱える
非数値は数字ではない非数値は表現できない非数値も計算対象なので、数字と同様に扱える
doubleの演算
  • double.NaN != double.NaN
  • double.IsNaN(double.NaN)
  • double.NegativeInfinity == double.NegativeInfinity
  • double.IsNegativeInfinity(double.NegativeInfinity)
  • double.IsInfinity(double.NegativeInfinity)
  • double.PositiveInfinity == double.PositiveInfinity
  • double.IsPositiveInfinity(double.PositiveInfinity)
  • double.IsInfinity(double.PositiveInfinity)
  • double.IsNaN(double.IsNaN と 任意のdoubleとの演算) // NaNに何をしてもNaN
  • double.IsNaN(0.0 / 0)
  • 1.0 / 0 == double.PositiveInfinity
  • -1.0 / 0 == double.NegativeInfinity
  • double.Epsilon + 0 == double.Epsilon
  • double.Epsilon * 1 == double.Epsilon
  • double.Epsilon + 1e-307 == 1e-307
  • double.Epsilon + 1e-308 != 1e-308
  • double.Epsilon * double.PositiveInfinity == double.PositiveInfinity
  • double.Epsilon * double.NegativeInfinity == double.NegativeInfinity
  • double.Epsilon / 0 == double.PositiveInfinity
  • double.MaxValue + 1e292 == double.PositiveInfinity
  • double.MaxValue + 1e291 != double.PositiveInfinity
  • double.MaxValue * (1 + 1e-15) == double.PositiveInfinity
  • double.MaxValue * (1 + 1e-16) != double.PositiveInfinity
  • double.MaxValue / 0 == double.PositiveInfinity
  • double.MinValue - 1e292 == double.NegativeInfinity
  • double.MinValue - 1e291 != double.NegativeInfinity
  • double.MinValue * (1 + 1e-15) == double.NegativeInfinity
  • double.MinValue * (1 + 1e-16) != double.NegativeInfinity
  • double.MinValue / 0 == double.NegativeInfinity
  • Math.Abs(double.MaxValue * double.Epsilon - 8.8817842e-16) < 1e-24
  • double.NegativeInfinity < 0
  • double.IsNaN(double.NegativeInfinity * 0)
  • double.IsNaN(double.PositiveInfinity * 0)
  • double.IsNaN(double.NegativeInfinity + double.PositiveInfinity)
  • double.IsNaN(double.NegativeInfinity - double.NegativeInfinity)
  • double.IsNaN(double.PositiveInfinity - double.PositiveInfinity)
  • -double.NegativeInfinity == double.PositiveInfinity
  • double.NegativeInfinity / 0 == double.NegativeInfinity
  • double.PositiveInfinity / 0 == double.PositiveInfinity
  • -1 / double.Epsilon == double.NegativeInfinity
  • 1 / double.Epsilon == double.PositiveInfinity
  • Math.Abs(1 / double.MaxValue - 5.562685e-309) < 1e-315
  • Math.Abs(1 / double.MinValue + 5.562685e-309) < 1e-315
  • 1 / double.NegativeInfinity == 0
  • double.MaxValue / double.NegativeInfinity == 0
  • double.MinValue / double.NegativeInfinity == 0
  • 1 / double.PositiveInfinity == 0
  • double.MaxValue / double.PositiveInfinity == 0
  • double.MinValue / double.PositiveInfinity == 0
  • double.IsNaN(double.NegativeInfinity / double.NegativeInfinity)
  • double.IsNaN(double.NegativeInfinity / double.PositiveInfinity)
  • double.IsNaN(double.PositiveInfinity / double.PositiveInfinity)
  • double.NegativeInfinity の符号を変えない演算は double.NegativeInfinity
  • double.NegativeInfinity の符号を変える演算は double.PositiveInfinity
  • double.PositiveInfinity の符号を変えない演算は double.PositiveInfinity
  • double.PositiveInfinity の符号を変える演算は double.NegativeInfinity

HttpListenerのサンプル。8080ポートを開けていれば、別マシンからもアクセス可能。
public static void HttpListenerSample()
{
	if (!HttpListener.IsSupported)
	{
		Console.WriteLine("Not supported");
		return;
	}
	HttpListener listener = new HttpListener();
	listener.Prefixes.Add("http://+:8080/sample/");
	try
	{
		listener.Start();
		while (true)
		{
            HttpListenerContext context = listener.GetContext();
			using (HttpListenerResponse res = context.Response)
			using (StreamWriter sw = new StreamWriter(res.OutputStream))
			{
				sw.WriteLine("<html><head><title>{0}</title></head><body>{0}</body></html>",
					"This is a sample");
			}
		}
	}
	catch (Exception e)
	{
		Console.WriteLine(e.Message);
	}
	finally
	{
		listener.Close();
	}
}


06/04/24(月)

似たようなことを 何度も書いているが、もう一度。
大学の演習でプログラミング課題をやったとき、ある人のソースを私は普通に読めるのに、 その人は私の書いたソースがわからないことがあって不思議に思ったことがある。 私のソースは必要最低限のことしか書いていないため、行数自体は半分くらいになっており、 私の方がわかりやすいはずである。その後、観察してみると、人のソースを読める人の方が 少ないことに気づいた。プログラミングの作成能力に個人差があるのはよく知られているが、 読解能力にも同じように個人差がある。
この差は、経験によるものもあるし、センスもあるだろう。相関はあるだろうが、 プログラミングを始めてからの期間だけで測ることも難しい。
プログラミング言語は、英語や日本語などの言語より覚えることは、はるかに少ない。 しかし、文法だけ覚えても、目的を達することはできない。必要なのは、調査やロジックや 設計力などの総合的な能力である。問題解決能力向上のため、問題解決の手段として もっとプログラミングを教えるべきではないだろうか。

06/05/12(金)

doubleの演算で、なぜ、 double.NaN != double.NaN なのだろうか。これは、NaNとの演算は全てfalseであるというルールのためである。 数学及び整数演算において、A op B は !(A not op B) と同値であるが、doubleではそうでない。 A op B と同値なのは、!(A not op B) && !double.IsNaN(A) && !double.IsNaN(B)である。 従って、!(d1 < d2) と同値なのは、d1 >= d2 || double.IsNaN(d1) || double.IsNaN(d2) である。

06/05/22(月)

外出ばかりで、ほとんど会社に 行ってなかったらメールが300通たまっていた。 中国語風のメールが実は日本語だったことが判明したが、原因も対応方法も不明。

ClickOnceで引数をとる方法。
まず、System.Deploymentを参照追加し、System.Deployment.Applicationをusingする。 applicationファイルのdeploymentタグに trustURLParameters="true"を追加。 VS 2005 ToolのVSコマンドプロンプトからMageUIを起動して修正してもよい。
public string[] GetArg()
{
	if (!ApplicationDeployment.IsNetworkDeployed)
		return DelOne(Environment.GetCommandLineArgs());
	string[] ss = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
	return ss == null ? new string[0] : ss[0].Split('&');
}
public string[] DelOne(string[] ss)
{
	if (ss == null || ss.Length == 0) return new string[0];
	string[] res = new string[ss.Length - 1];
	for (int i = 0; i < res.Length; ++i) res[i] = ss[i + 1];
	return res;
}
これが何故かうまくいかない。
ApplicationDeployment.CurrentDeployment.Update()やApplication.Restart()というのもある。


06/06/29(木)

ノートPCが壊れて 3週間。新PC(CF-Y5)も来てようやく仕事ができる環境になった。 最新バックアップのDVD-RAMも壊れていたが、最新でないものからリカバリーした。 メーラーもこれを機にThunderbirdに変更した。面倒なので昔のメールは戻さなかった。 Thunderbirdの迷惑メールフィルタはかなり優秀だ。 ついでなので、モニタもデュアルにした。
来週からは社内の体制が大きく変わる。

最近とここ半年ぐらいの読書録。 isbn:4758432333,isbn:4334738427,isbn:4087460371,isbn:4839919844,isbn:4334033415, isbn:4774126934,isbn:4885553075,isbn:4885552818,isbn:4774125237,isbn:4627826613, isbn:4797332743,isbn:4797336021,isbn:4413007875,isbn:4798106038,isbn:479732158X, isbn:4413041208,isbn:4845407353,isbn:4101230323,isbn:4047100080,isbn:4757207743, isbn:4492531947,isbn:4478420491,isbn:4774122327,isbn:4150502897,isbn:448811802X, isbn:4048736140,isbn:404788152X,isbn:4594004539,isbn:4757211295,isbn:4000280716, isbn:4000280724,isbn:4000280732,isbn:4000280740,isbn:4000280759,isbn:4478374813


06/07/07(金)

ドットネットの再配布可能パッケージは、 dotnetfx.exe と langpack.exeの両方必要なようだ。
http://www.microsoft.com/downloads/details.aspx?FamilyId=0856EACB-4362-4B0D-8EDD-AAB15C5E04F5&displaylang=ja
http://www.microsoft.com/downloads/details.aspx?FamilyId=39C8B63B-F64B-4B68-A774-B64ED0C32AE7&displaylang=ja

06/07/12(水)

XmlSerializerで、あるメンバの メンバ名のタグを出さないようにするには、XmlTextをつければいい。

06/07/18(火)

会社で引越し 。とりあえず一段落。非常勤の準備をしないと。

06/07/19(水)

最長のパスを求める方法は、 IPに定式化する方法が一般的なようだ。実用的にはその方がいいだろうが、作るのはちょっと面倒だ。 以下に全探索する方法を紹介する。計算量は指数オーダなので、複雑なものはできない。
/// <summary>
/// グラフ上の最長路のホップ数を返す
/// (有向アークが含まれていてはいけない)
/// </summary>
public static int GetLongestPath<TN, TA>(Graph<TN, TA> grp)
{
	foreach (ArcTag<TN, TA> at in grp.ArcTags)
		if (at.IsEnable && at.IsDirected) throw new ApplicationException("Exist directed arc");
	bool[] unchk = new bool[grp.ArcsCount]; // 未チェックのアークか
	int[] degree = new int[grp.NodesCount]; // ノードの次数
	foreach (ArcTag<TN, TA> at in grp.ArcTags)
	{
		if (unchk[at.Index] = (at.IsEnable && at.LeftTag.IsEnable && at.RightTag.IsEnable))
		{
			++degree[at.LeftID];
			++degree[at.RightID];
		}
	}
	List<GLPData> dt = new List<GLPData>(); // 次数が2のノードを縮約した後のリンクの集合
	GLPData gd = new GLPData();
	Dictionary<int, int> dic = new Dictionary<int, int>(); // ノードIndex→縮約後のノードIndex
	// 縮約する
	while (true)
	{
		ArcTag<TN, TA> fnd = null, fst = null;
		for (int i = 0; i < grp.ArcsCount; ++i)
		{
			if (!unchk[i]) continue;
			ArcTag<TN, TA> at = grp.ArcTag(i);
			if (fst == null) fst = at;
			if (degree[at.LeftID] == 2 && degree[at.RightID] == 2) continue;
			fnd = at;
			break;
		}
		if (fnd == null && (fnd = fst) == null) break;
		// 縮約後のノード数が31以上なら求められない
		if (dt.Count >= 31) throw new ApplicationException("Too complex");
		NodeTag<TN, TA> nt = degree[fnd.RightID] != 2 ? fnd.RightTag : fnd.LeftTag;
		gd.len = 0;
		gd.node1 = GetIndex(dic, nt.Index);
		while (true)
		{
			unchk[fnd.Index] = false;
			++gd.len;
			nt = grp.NodeTag(fnd.AnotherID(nt.Index));
			if (degree[nt.Index] != 2) break;
			foreach (ArcTag<TN, TA> act in nt.InArcTags)
			{
				if (act.IsEnable && act != fnd)
				{
					fnd = act;
					break;
				}
			}
			if (!unchk[fnd.Index]) break;
		}
		gd.node2 = GetIndex(dic, nt.Index);
		dt.Add(gd);
	}
	if (dt.Count == 0) return 0;
	int[] con = new int[dic.Count]; // 縮約後のノードの次数
	int[] src = new int[dic.Count]; // 0:非対象、1:未チェック、2:チェック済み
	bool[] bUse = new bool[dt.Count]; // 縮約後のリンクのON/OFF
	int max = 0, cur = 0, odd = 0;
	uint n = 1U << dt.Count;
	// リンクのON/OFFの全組合せをチェック
	for (uint i = 0; i < n - 1; ++i)
	{
		int k = (int)Math.Log((i | ~(~i - 1)) - i, 2);
		gd = dt[k];
		int sgn = (bUse[k] = !bUse[k]) ? 1 : -1;
		cur += sgn * gd.len;
		odd += (con[gd.node1] += sgn) % 2 == 0 ? -1 : 1;
		odd += (con[gd.node2] += sgn) % 2 == 0 ? -1 : 1;
		// 次数が奇数の数が3以上なら一筆書きでない
		if (odd > 2 || cur <= max) continue;
		// 連結性のチェック
		bool bFound = false;
		for (int h = 0; h < src.Length; ++h)
		{
			src[h] = con[h] == 0 ? 0 : (bFound ? 1 : 2);
			if (src[h] > 0) bFound = true;
		}
		while (bFound)
		{
			bFound = false;
			foreach (GLPData gld in dt)
			{
				if (src[gld.node1] + src[gld.node2] == 3)
				{
					bFound = true;
					src[gld.node1] = src[gld.node2] = 2;
				}
			}
		}
		for (int h = 0; h < src.Length; ++h)
			if (bFound = src[h] == 1) break;
		if (!bFound) max = cur;
	}
	return max;
}
private struct GLPData
{
	public int len;
	public int node1;
	public int node2;
}
private static int GetIndex(Dictionary<int, int> dic, int i)
{
	int k;
	if (!dic.TryGetValue(i, out k))
		dic.Add(i, k = dic.Count);
	return k;
}

06/07/31(月)

dot NET Remotingを使った 簡単なチャットプログラム。Registやサーバ名を直せば、複数マシン間でも通信可能。通常はサーバのメソッドはlockすべき。また、ネットワーク断を考慮してサーバコールはtry-catchすべき。
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
	if (e.KeyCode != Keys.Enter) return;
	svr.Add(textBox1.Text + "\r\n");
	textBox1.Text = "";
}
public class Server : MarshalByRefObject
{
	private string data = "";
	public string Data { get { return data; } }
	public void Add(string s) { data += s; }
}
Server svr;
private void Form1_Load(object sender, EventArgs e)
{
	const int portno = 8100;
	System.Diagnostics.Process[] prcs = System.Diagnostics.Process.GetProcessesByName("SimpleChat");
	if (prcs.Length == 1)
	{
		System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(
			new System.Runtime.Remoting.Channels.Tcp.TcpChannel(portno), false);
		backgroundWorker1.RunWorkerAsync();
		System.Threading.Thread.Sleep(100);
	}
	svr = (Server)Activator.GetObject(typeof(Server), "tcp://localhost:" + portno + "/SimpleChat");
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
	System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownServiceType(
		typeof(Server), "SimpleChat", System.Runtime.Remoting.WellKnownObjectMode.Singleton);
}
private void timer1_Tick(object sender, EventArgs e)
{
	timer1.Stop();
	string s = svr.Data;
	if (textBox2.Text != s) textBox2.Text = s;
	timer1.Start();
}

非常勤が終了。今年でお終い。


06/08/23(水)

プロジェクトがいろいろ始まる。

IEで、あるシステムにログインするときに、パスワードを覚えさせていると便利だが、 危険でもある。このデータの場所をTrueCryptのドライブにして、ログアウト/休止状態で自動アンマウント、 ログイン/休止復帰で自動マウントできると便利なんだが。


06/08/28(月)

数学関連の話題。

その1「子供に因数分解の必要性をどう教えるか」 http://q.hatena.ne.jp/1155690321
自分の子供にだったら、やっぱり、「受験で必要だから」って言うと思う。あるいは、 「覚えると、その先の楽しいことがわかるようになるから」とか。

その2「ギャンブル必勝法?」 http://g540414.blog10.fc2.com/blog-entry-55.html
これはマルチンゲールですね。宝くじや保険の逆で、「たいていはちょっと儲かり、ごくまれに大損する」ものです。 当然、勧められるものではありません。話は変わるけど、情報処理が進んである種の情報が確実に取得できるように なったら関連する保険は極限まで安くできるんじゃないかな。

その3「ダイヤの確率は?」 http://d.hatena.ne.jp/daiya591/
単純に条件付確率になり10/49ですね。1/4という人多すぎ。
似たような問題。http://plaza.harmonix.ne.jp/~k-miwa/magic/something/diamond4.html
Bの処刑される確率は2/3のままである。問題文では、「AまたはCを教えて欲しい」と言っているので、 分母は「Aが処刑されるケースとCが処刑されるケース」であるからだ。 何の脈絡もなく「Aが処刑される」と知れば、確率は1/2となる。これは、分母が「Aが処刑される」だけになるから。


06/09/13(水)

PowerShellを入れようとした。 最初に「[V] Never run [D] Do not run [R] Run once [A] Always run [?] Help」と聞かれて、「V」と答えたの。、 「A」に直そうと思い、アンインストールして再インストールしようとしたところ、 「ソフトウェア制限ポリシーで許可されていません」と出てインストールできない。 いろいろ調べてみると、証明書が信用できなくなっているようだ。コンパネの設定を探すも見つからず。 インターネットのオプションの証明書の中の「信頼されない発行元」の該当証明書を削除してやっとインストールできた。

06/09/15(金)

XPでzipフォルダを解除する 方法が出てた。
regsvr32 /u zipfldr.dll
regsvr32 /u cabview.dll
WinZipを使っているので、zipフォルダの意味がないので解除してみた。 確かに、早くなったような気もする。

PowerShellの勧めを作った。
PowerShell.ppt
行列クラスを追加してLoadFromしておくと面白いかも。


06/09/22(金)

ubuntuでMonoを 動かしてみた。GUIも結構、動く。完全ではないが。 商用で使ってるとこあるのかな。

06/10/02(月)

共感した話。
自然選択の最適化能力とその限界
http://game.g.hatena.ne.jp/Nao_u/20051005

私は入社以来 十数年、組合せ最適化の仕事ばかりしている。しかも、出来上がっているソリューションを提供しているのではなく、 顧客の問題を聞いてから、その度に解決策を考えている。こんなことを続けているのは、社内でも私だけだし、社外にも少ないと思う。 顧客は、通信系が多いが多岐に渡る。そこで、たまに思うのが「そんなに最適化して意味があるのか?」ということである。
例えば、最適解を100%としよう。90%ぐらいまでだったら簡単に行くことも多い。95%だと手間が増える。 98%だと、えらい面倒だ。99%とか100%だと、ほぼ無理である。
最適化とは、無駄をなくすことである。 でも、無駄とは余裕のことでもある。余裕を無くすとどうなるか。変化に対応できなくなる。だから、無駄を無くすことはよくないことにもなると思う。 バランスの取れた最適化をすべきなのだろう。そういうことは、大学では教えない。この話は、学会でもしたが、共感は持ってもらえなかった。

東京タワーでは堪えたが、イキガミ第4話を立読みで泣いてしまった。


06/10/12(木)

プロジェクト リーダで8個、並走中。2個はほぼ終わり、2個はまだスタートせず、2個はまかせきりだが。

06/10/31(火)

特定の人に 出すべきメールを間違ってメーリングリストに出している人がいた。 メーラがこのようなケースをチェックしてくれるとうれしいだろう。 ベイズ理論を使えば、50%ぐらいの確率でできるんじゃないだろうか。 (構文解析せずにパターンマッチングだけで)

06/11/06(月)

宇宙物流シミュレータを作りたい。

06/11/17(金)

Mono1.2をubuntuに入れた。 GUIインストールはこけるが、--textでOKだった。 Windowsでコンパイルした2.0バイナリは動いたが、ジェネリクスを使ったコンパイルはできない。 -langversionにISO-1とDefaultしかない。なぜ?

プログラミング所感 - 前へ 目次次へ