前回のコードを C# で書いてみようと何故か思った。
書いていて気がついたのだが C# は百桁程度の整数も扱えない。
そういえば C++ も扱えない、今まで int64 までしか使ったこともない。
あぁ GMP ってそのことだったんだ。
Python や Ruby の整数は桁数が無限なので気がつかなかった。
てゆーか無限に扱える意味ってようするに数学の世界だと。
多倍長整数っていうんだね。
ググると BigInteger というのが見つかった。
CodeProject: C# BigInteger Class. Free source code and programming help
まあよく解らないものは使って覚えるのが一番早い。
クラスなので普通に new したあとは整数のように扱えるはず。
落としてプロジェクトに含めてみる。
いきなり困った、べき乗 Math.Pow() は double しか扱えない。
いや、考えてみたら計算は Math でやらなきゃいけないわけではない。
自分で for ループさせても何も問題無い、ここまではすぐに思いついた。
でもそれをどう計算…つまらないことに詰まってしまったり。
なんとか百桁に成功したところで一万桁とかにすると例外スロー。
private const int maxLength = 70;
この数値が関係あるらしい、大きな桁にするときは増やして使う。
まあとりあえずそんなこんなで書いてみたコード。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | using System; using System.Diagnostics; namespace pi1 { class Test { // System.Numeric.BigInteger はまだない BigInteger p, q; BigInteger expansion( int n) { BigInteger x, nn, c, s, k; x = new BigInteger(0); nn = new BigInteger(0); c = new BigInteger(0); s = new BigInteger(0); k = new BigInteger(0); x = (p * q) / n; nn = n * n; c = 1; s = x; k = 1; while (x > 0) { x = x / nn; k = k + 2; c = -c; s = s + c * (x / k); } return s; } public void pie() { Console.WriteLine( "円周率を計算します。" ); Console.WriteLine( "桁数を指定してください" ); int prsn = int .Parse(Console.ReadLine()); p = new BigInteger(1); q = new BigInteger(1); Stopwatch sw = new Stopwatch(); sw.Start(); for ( int i = 1; i <= prsn; i++) p *= 10; for ( int i = 1; i <= 10; i++) q *= 10; BigInteger y, u, v; y = new BigInteger(0); u = new BigInteger(0); v = new BigInteger(0); y = 4 * ( 12 * expansion(18) + 8 * expansion(57) - 5 * expansion(239) ); y = y / q; u = y / p; v = y - u * p; sw.Stop(); Console.WriteLine( "{0}.{1}" , u, v); Console.WriteLine( "計算時間={0}" , sw.ElapsedMilliseconds / 1000.0); Console.Read(); } } class Program { static void Main( string [] args) { Test t = new Test(); t.pie(); } } } |
初期化の引数は BigInteger でもいいはずだけど怖いので int に。
あまり意味は無い。
IronPython より十倍速いわな、BigInteger が早いのだろうか。
それよりやはり .NET もコンパイルしたほうが早いということだろうけど。
とはいえ CPython にはボロ負けのまま…
せめてマルチスレッド化したほうが…意味があるかは置いておいて。
実用アプリじゃ全く問題無いことだし。
C 言語は面倒くさいので上記のとかを試す。
百万桁でたったの 39 秒だもの、この差をどうこうしようとか思わないわ。
手元に IronPython 1.1 が残っていたので前回のコードを試す。
0.098 秒…あれ?二倍も速くなった、DLR ってもしかして絶望的に遅い?