|
/*========================================================*/ <<<あゆしゃのC言語プログラミング>>> /*========================================================*/ 第460回 平方根の残骸 発行 2004年6月11日(金曜日) 発行数 約2900 {magclick} /*========================================================*/ はじめに ( 決り文句 ) /*========================================================*/ ・このメールマガジンはまぐまぐさんから発行しています。 ・ジャンルは、マルチメディアのプログラム、C言語です。 ・このメールマガジンは、横60文字で作成しています。 また、インデントはすべて半角スペース4つで構成しています。 ・ここで扱うプログラムは、C言語と半光年以内のものです。 ・登録解除は、まぐまぐさんのホームページでお願いします。 ・まぐまぐさんのバックナンバー(下欄参照)を活用して下さい。 ・ここは私の復習の場です。内容は約1ヶ月内外に私が勉強した 内容になっています。最新の技術があれば、へたれもあります。 ・わかりやすさを優先させる為、たまに嘘があるかもしれません。 ・セキュリティ突破のため、暗号化された単語があります。 /*========================================================*/ ご挨拶 /*========================================================*/ こんにちは。あゆしゃです。 先日、このようなページを見付けました。 http://park3.wakwak.com/~ore/ 中でも、このページがお勧めです。(リンクフリー) http://park3.wakwak.com/~ore/application/telmemo/index.html なかでも、シャア専用がお勧めです。シャア専用ですよ! 先日、株の売買ゲームに登録しました。 野村のバーチャル株式投資倶楽部 http://www2.nomura.co.jp/vstock/VirtualServlet? 仮想のお金(初期値:100万円)と、実際の株式の状態を元に 資金を増やすゲームです。 参加費は無料で、扱われる株式の値段は本物ですので、株の お勉強に最適です。 私は木曜日現在、999,865円です。(49,945番/90,783人中) やや、下がってしまいました。 しかし、大分となれたもので、1位の人の金額が9900万円だ という新事実を把握できるまでになりました。 10億円と勘違いしたのは、桁を1つ読み間違えていたよう です。 {magclick} /*========================================================*/ 今回のお題 << 平方根の残骸 >> /*========================================================*/ あゆしゃが平方根のアルゴリズムを考えるようになったきっかけ は、ガウスさんでした。 http://www.vector.co.jp/soft/dl/win95/personal/se119757.html ガウスさんのヘルプにて、ニュートン法という言葉を初めて目に して、衝撃を受けたのです。 そこで、ニュートン法とは何ぞやと、調べたところ、このページ を見付けました。 http://www.sm.rim.or.jp/~shishido/newton.html ここにあったプログラムを真似して、このプログラムを作ったの が、あゆしゃの初めての平方根です。 // while( x * x < a ) x++; // 二乗がaを超える最小のxを求める for( cnt = 0; cnt < 10; cnt++ ) { // 精度レベル x2 = x; x = ( x + a / x ) / 2; // 二乗してaになるxに近づける if( x2 == x ) break; // 結果がかわらなくなったら終了 } とりあえずインクリメントは馬鹿なのではずして、後は精度 レベルをどうしようかなぁと、考えました。 しかし割り算がどうしても嫌でした。 ★そこで、インクリメントに注目しました。 インクリメントは、数列を線形検索しているわけなので、すこし はしょれないかと、思ったのです。 そうして考えているとき、平方根が0〜65535の中に必ず 存在するということに気がつきました。 そこで、検索だけで最後まで求められるはずだと思ったのです。 for( x = 30000; x < 65500; x += 30000 ) if( a < x * x ) break; for( x2 = x, x = x - 10000 + 1000; x < x2; x += 1000 ) if( a < x * x ) break; for( x2 = x, x = x - 1000 + 100; x < x2; x += 100 ) if( a < x * x ) break; for( x2 = x, x = x - 100 + 10; x < x2; x += 10 ) if( a < x * x ) break; for( x2 = x, x = x - 10 + 1; x < x2; x += 1 ) if( a < x * x ) break; x++; // これがないと誤差が10万回に1回の確率で出てしまう はじめはこのように、10進数で考えていました。 そしてこれを、もっと速くしようと思ったのです。 for( x = 30000; x < 65500; x += 30000 ) if( a < x * x ) break; for( x2 = x, x = x - 30000 + 10000; x < x2; x += 10000 ) if( a < x * x ) break; for( x2 = x, x = x - 10000 + 2000; x < x2; x += 2000 ) if( a < x * x ) break; for( x2 = x, x = x - 2000 + 400; x < x2; x += 400 ) if( a < x * x ) break; for( x2 = x, x = x - 400 + 80; x < x2; x += 80 ) if( a < x * x ) break; for( x2 = x, x = x - 80 + 16; x < x2; x += 16 ) if( a < x * x ) break; for( x2 = x, x = x - 16 + 4; x < x2; x += 4 ) if( a < x * x ) break; for( x2 = x, x = x - 4 + 1; x < x2; x += 1 ) if( a < x * x ) break; x++; // これがないと誤差が10万回に1回の確率で出てしまう IF が増えただけですが(笑)。 しかしあまり速くなく、この方法に限界を感じました。 さらに、誤差が出てしまうのが悩みの種でした。 ★そこで、ふとひらめいたのです。2進数にしようと! for( x = 32768, cnt = 16384; cnt; cnt >>= 1 ) { if( a >= x * x ) x += cnt; else x -= cnt; } x += 2; これはかなり速く、やばいと思いました。 もっとやばくしようと、ループを展開しました。 if( a >= 32768*32768 ) x = 32768+16384; else x = 32768-16384; if( a >= x * x ) x += 8192; else x -= 8192; if( a >= x * x ) x += 4096; else x -= 4096; if( a >= x * x ) x += 2048; else x -= 2048; if( a >= x * x ) x += 1024; else x -= 1024; if( a >= x * x ) x += 512; else x -= 512; if( a >= x * x ) x += 256; else x -= 256; if( a >= x * x ) x += 128; else x -= 128; if( a >= x * x ) x += 64; else x -= 64; if( a >= x * x ) x += 32; else x -= 32; if( a >= x * x ) x += 16; else x -= 16; if( a >= x * x ) x += 8; else x -= 8; if( a >= x * x ) x += 4; else x -= 4; if( a >= x * x ) x += 2; else x -= 2; if( a >= x * x ) x += 1; else x -= 1; x += 2; 現在のもののほとんどが、このときに完成しました。 しかし、あゆしゃに立ちはだかる壁がありました。 誤差が出るのです。 +2でごまかしていますが、完全ではありませんでした。 そこで、エラーになる数字をざーーーーーーーーーっと並べて、 どうやればエラーを防げるかを考えました。 そこで、 // 求める値を超える状態にする 実行されない場合もある if( a > x * x ) x++; // 求める値を初めて下回る状態にする(小数点以下を切捨てる) // 実行されない場合もある if( a < x * x ) x--; この2行の補正を、編み出したのです。 リリアンのように。 コメントには、おっかなびっくり感が残っていますね。 {magclick} /*========================================================*/ さいごに /*========================================================*/ 新C言語使いにおくるチョー基本講座 第6回。 プログラミングの作業を早く片付けようと思う場合、私は長い プログラムを書くようにしています。 長い、つまり丁寧なプログラムです。 本文の、「ざーーーーーーっと」と、同じことです。 1行で書けるやん、というものでも、丁寧に、なでるように、 組み立てます。 最初は、自分自身も処理に精通していないため、あまり トリッキーなことをしてしまうと、やばいのです。 それから、少し余裕が出たら、プログラムを小さく再構成 します。 バグはプログラム量と比例するといいますので、小さい プログラムのほうが、バグが少ないのです。 再構成、っていうか、作り直しです。 ★実はこれが楽しい^^; 丁度そのころ、私はコメントを書きます。 初めてプログラムを書くときは、コメントは面倒くさいし、 しかし3日たつとプログラムがわからなくなるので、 必死こいてコメントを書きます。 最善なのは、初回に書くことなのですけれども。 {magclick} /*========================================================*/ 次回予告 /*========================================================*/ 次回は6月16日(月曜日)に、第461回をお送りします。 お題は「平方根の少数」 あゆしゃ法は、何も変更することなく、小数を計算できます。 どうするのでしょうか? そのヒントは平方根シリーズの冒頭で、すでに説明しました。 お楽しみに! /*========================================================*/ 最後の決り文句 /*========================================================*/ このメールマガジンは、まぐまぐさんから発行しています。 このメールマガジンを解除したい場合は、まぐまぐさんをご利用 ください。このメルマガのまぐまぐアイディーは最後にあります。 このメールマガジンには広告が挿入されていますか? このメールマガジンの内容に文面の引用はありませんか? めーらっくすの場合はめーらっくすの利用方に従ってください。 このメールマガジンの内容の、転用、流用、宣伝、リンク、 宝くじが当たりますように! なんて大歓迎です。 {magclick} /*========================================================*/ /*========================================================*/ 発行者 あゆしゃ ホームページ::あゆしゃの世界 http://ayusya.hp.infoseek.co.jp/ ご意見・ご感想・ご質問メール mailto:ayusya@flamenco.plala.or.jp まぐまぐ::アイディー 0000020674 まぐまぐ::登録と解除 http://www.mag2.com/m/0000020674.htm まぐまぐ::バックナンバー http://jazz.tegami.com/backnumber/frame.cgi?id=0000020674 めーらっくす::アイディー MM3E1AEE285AB4F めーらっくす::登録と解除 http://www.mailux.com/mm_dsp.php?mm_id=MM3E1AEE285AB4F めーらっくす::バックナンバー★最近のものならこちらが便利★ http://www.mailux.com/mm_bno_list.php?mm_id=MM3E1AEE285AB4F |