IronPython」タグアーカイブ

C# でぱい

前回のコードを 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;

この数値が関係あるらしい、大きな桁にするときは増やして使う。
まあとりあえずそんなこんなで書いてみたコード。

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 に。
あまり意味は無い。

cs_pi

IronPython より十倍速いわな、BigInteger が早いのだろうか。
それよりやはり .NET もコンパイルしたほうが早いということだろうけど。

とはいえ CPython にはボロ負けのまま…
せめてマルチスレッド化したほうが…意味があるかは置いておいて。
実用アプリじゃ全く問題無いことだし。

FFTとAGMによる円周率計算プログラム

C 言語は面倒くさいので上記のとかを試す。
百万桁でたったの 39 秒だもの、この差をどうこうしようとか思わないわ。

手元に IronPython 1.1 が残っていたので前回のコードを試す。
0.098 秒…あれ?二倍も速くなった、DLR ってもしかして絶望的に遅い?

ぱい

super pi を作ろう – ぴょぴょぴょ? – Linuxとかプログラミングの覚え書き –

というのを見つけた。
正直よく解らないけど(だから素人のままなんだ…)
super pi みたいなのを自作するのは面白そう、もっと勉強せねば。

とにかく Python でπの無限出力はどうすればいいのだろう?
スクリプト言語はこの手の計算は不得意だと解っているけどやってみたい。

math.pi では小数点以下 16 桁までしか出力してくれないし。

B. 浮動小数点演算、その問題と制限

ということで Web を探す。
とにかく例の一つでもないと私のような素人はさっぱり解らない。

情報処理 II, 第6回

簡単に見つかった…
早速 circleratio.py というのを落として実験。
エンコードが何故に latin-1 ? utf-8 に変更しておこう。

print はきちんと括弧でくくったのに例外出まくリング…

そういえば Python 3 って他にも沢山変わっていたんだっけか。

特集:もっと知りたいPython3000|gihyo.jp … 技術評論社

input() は eval(input()) にしないと文字列になるので書き換えて。
/ は // にしないと float になっちゃうので書き換えて。

#!/bin/env python
#-*- coding: utf-8 -*-
# 2007.4.9
#
# ガウスの公式による円周率の計算

from math import *  # 数学関数を使うためのまじない
from time import *  # 時間関数を使うためのまじない
from sys import *   # システム関数を使うためのまじない

# arctan(1/n) の小数展開
def expansion(n):
    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

print ('円周率を計算します。')
print ('桁数を指定してください。')
prsn = eval(input())

t0 = time()     # 開始時刻
p = 10**prsn
q = 10**10

y = 4 * ( 12 * expansion(18) + 8 * expansion(57) - 5 * expansion(239) )
y = y // q
u = y // p
v = y - u * p
t1 = time()     # 終了時刻

print ("%d.%d" % (u,v))
print ('計算時間 =', t1 - t0)
fin = stdin.readline()  # Enter キーで終了

メンドクセ!
40 行のコードでコレでは大きなプログラムはマジ大変だろうなぁ。

そういえば math,time,sys は IronPython にも組み込まれているはずだよなぁ。
やってみたら一行目を消さなきゃエンコードを認識しないかやはり。
Linux の IronPython は何故か imput() ができなのでパス。

pi

IronPython 遅っ!
コンマ付きの print もおかしいし、やはり普通の Python 代わりは無理だわ。

しかし実行中は見事にデュアルコア CPU の 50 %利用ってのが笑えるよ。
ちなみに AMD Athlon64 X2 4200+ と AMD 690G というショボい構成のまま。

picpu

十万桁に 89 秒も掛かった、百万桁なんて恐ろしくて出来ん。
つか、こういうのはやはり C 言語でやるべきだよと。

えむえでぃた

とりあえず Windows での Python は EmEditor で行こうと思う。
一応こんな設定にしてみた。

emedit

Home キーでカーソルをインデントの先頭に行かせる。
Shift+Tab でインデント分カーソルを戻す。
という動作は秀丸ではできないっぽいんで。

PyScripter なんてのも見つけたけど普通のテキストエディタのほうがエエわ。
スクリプト言語を IDE で書くなんて馬鹿げていると思うようになったよ。
更に言語ごとに別の IDE だなんて何がしたいの?みたいな。

とりあえずコイツにはスニペットプラグインもあるしガンガン登録してしまえ!
と思ったけどこのスニペットって単語登録ができるだけっぽいな。
それも Tab キーで補完じゃなく選択して Enter なんだ、ガッカリ。

まあ EmEditor はアウトプットがあるから便利だ。
と思ったけど…

output

おもくそ文字化けしとるやないの。
コンソールなら普通に表示できるのになんやこれ、ガッカリ。

それとツールに Python と IronPython を登録。
これでボタンを選ぶだけでどちらも動作確認ができるぞと。
アウトプットが化けるから pythonw.exe でなく python.exe にしておくか…

Ruby も一応ツールに登録していたんだけど全く使わないので登録解除。
IronRuby なんてもう忘れられた子になっている、そんなのあったなぁ…

他に VL ゴシックにしたり読み書きは BOM 無し UTF-8 に指定したり。
なんか意地でも Ubuntu の gEdit に合わせようとしている自分が怖い。

しかし弄くれば弄くるほど Windows と Linux の文化の違いを感じるよ。
テキストエディタに求められているものが違いすぎ。

追記

アウトプットの文字化けは私の設定ミスだった…
出力エンコードを UTF-8 にしていた、システム規定でよかったのね。
江村さんごめんなさい。

それと Shift+Tab の動作だが Tab 分カーソルが戻るだけだった。
文字列を選択していない場合は逆インデントをやってくれない。
これは困る、逆インデントに BackSpace を4回叩くなんてやってられないよ。

しかたがないのでマクロを作る。

if (document.selection.IsEmpty) {
	document.selection.DeleteLeft(4);
} else {
	document.selection.UnIndent(1)
}

を作り Shift+Tab の割り付けをコッチに変更という強引なワザで。
これで範囲選択状態の動作は維持しながら未選択の場合は前方四文字削除だ。
というか gEdit と同じ動作。

問題はインデントの先頭で実行することしか考えていないことだったりする。

IronPython で WPF

IronPython には nt という os の代替モジュールがあることを今更知った。
ということは前回のコードは

# -*- coding: UTF-8 -*-

# 環境変数の書き出し

import nt

keys = nt.environ.keys()
result = ""
for key in keys:
	result += key + "\n" + nt.environ[key] + "\n\n"

f = open("env2.txt", "w")
f.write(result)
f.close()

あーあ、os を nt に書き換えるだけで動いてしまったお。
open() とかは組み込み関数だからそのまま使えるし。

とはいえ IronPython ではコッチで書く人はほとんどいないだろう。
C# コードからの変換ばかりやるはめになるのは目に見えているし。

ということで

の本で WPF アプリのコードがあまりに不親切だったので補完。
部品を作るのにいきなり XAML を利用では IronPython の意味が無いでしょみたく。
XAMLPAD では Glade のようにはいかないと思うし、機能がショボすぎる。

マイレビューを一つ、CPython コードを書くのにも少し役に立ったよと。
ちなみに上記の nt モジュールの存在はコレを読み直して知った…
しかし mono の本同様にコレしかなく選べない状態が続いているのは悲しい。

さて最小限のコードを書いてみる。

# -*- coding: UTF-8 -*-

import clr

# 最小限下記ライブラリ(dll)が必要
clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")

import System

w = System.Windows.Window()
w.Title = "実験"
a = System.Windows.Application()
a.Run(w)

最小限のライブラリとは VC# とかを持っている人なら解るかな?
ソリューションエクスプローラにある参照設定以下のことね。
VC# なら右クリックして「参照の追加」をするけど IronPython はコードで行う。

se

本当は System も必要だけど最初から含まれているっぽい。

後、上記の本ではいきなり from 文を使っているけど理解してから使いましょう。
Window や Application というクラスは System.Windows 名前空間にあります。

知っていると思うけど Python の名前空間はモジュール名そのままである。
partial 指定ができないのが場合によっては辛いかもしれない。
boo という Python そっくりな言語はココの画像を見るとできるっぽい。

【ハウツー】F#、IronPython、Booまで使えるフリーの統合開発環境「SharpDevelop」 (3) 利用できるプログラミング言語 | エンタープライズ | マイコミジャーナル

まあそれはよくて。
上記を拡張しても後々で困るのでさっさとクラスに変更します。

# -*- coding: UTF-8 -*-

import clr

# 最小限下記ライブラリ(dll)が必要
clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")

from System import *
from System.Windows import *

class TestWin(Window):
    def __init__(self):
        self.Title = "class の実験"
        self.Closing += self.onClosing
    
    def onClosing(self, sender, e):
        MessageBox.Show("閉じます")

if __name__ == "__main__":
    w = TestWin()
    a = Application()
    a.Run(w)

やっぱり面倒なので from を利用、これで C# の using と同じ意味。

VC# で作るのと同じように Window を継承したクラスを __main__ で作る。
最後に Application インスタンスの Run() にぶち込めばクラス化は完了である。
これで C# コードからの変換が簡単になりました。

ついでに終了時にダイアログを出すようにハンドラを追加してみた。
Python のクラスなので引数に必ず self が必要です、よく忘れるんだこれが。

最後にコントロールを追加してみます。
XAML を使わずにコードで作る方法をば。

# -*- coding: UTF-8 -*-

import clr

# 最小限下記ライブラリ(dll)が必要
clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")

from System import *
from System.Windows import *
from System.Windows.Controls import *

class TestWin(Window):
    def __init__(self):
        self.Title = "Controls"
        # ボタン作成及びクリックハンドラ登録
        button = Button()
        button.Content = "ボタンだよ"
        button.Click += self.onClick
        # 一行エディットの作成
        # 内容を他で使うのでアトリビュートにしておく
        self.textbox = TextBox()
        self.textbox.Text = "なんか書け"
        # TextBlock の作成
        tb = TextBlock()
        tb.Text = "何か書き込んでボタンを押してね"
        # レイアウタを作成してこれらをセット
        sp = StackPanel()
        sp.Orientation = Orientation.Vertical
        sp.Children.Add(button)
        sp.Children.Add(self.textbox)
        sp.Children.Add(tb)
        # レイアウタを Window にセット
        self.Content = sp
        # この指定でコンテンツの大きさ固定なウインドウになる
        self.SizeToContent = SizeToContent.WidthAndHeight
        self.ResizeMode = ResizeMode.NoResize
    
    def onClick(self, sender, e):
        MessageBox.Show(self.textbox.Text)

if __name__ == "__main__":
    a = Application()
    a.Run(TestWin())

Button 等のクラスは System.Windows.Controls にあるので import する。
Window や Button に何かを乗せるには Content プロパティに代入する。
レイアウタにコントロールを追加するには Children.Add() メソッドを利用する。
という簡単な例である、最後に Run() の中で Window を作る小技をば。

seira

C# でウインドウをコードで作った人なら解るだろうけどほとんど同じに書けます。
C++ から Pascal への変換を経験した人なら「え?それだけ???」ですよね。
今回はここまで。

環境変数の対応リストを作る

Windows では os.environ[“HOME”] が例外になってしまった。
環境変数が違うようだ、Windows が用意しているのってどんなのがあるのだろう?
C++ では Windows SDK に個別取得する関数があるのであまり気にしていなかった。

今後のプログラム用に環境変数の対応リストが作りたい。

ということで environ のキーと値を書き出す簡易スクリプト。
Windows でも Linux でも動きます、一応 Windows 版は Python 3.0 で試した。
print でリダイレクトしたほうが今の私は早いけど Python だけでやってみよう。

#! /usr/bin/env python
# -*- coding: UTF-8 -*-

# 環境変数の書き出し

import os

keys = os.environ.keys()
result = ""
for key in keys:
	result += key + "\n" + os.environ[key] + "\n\n"

f = open("env.txt", "w")
f.write(result)
f.close()

ちなみに私の環境ではこうなった(合体しています)

env.txt

同じモンがありゃしねぇ、こりゃ環境変数を利用したコードの共有は無理だ。
どうでもいいけど Windows 用 Python での \n は CRLF になるんだね。

ちなみに IronPython では下記の要領で同じことができます。

# -*- coding: UTF-8 -*-

import System

# IronPython は clr なので \n では LF 固定になってしまう
nn = System.Environment.NewLine

# IDictionary が返る
dic = System.Environment.GetEnvironmentVariables()
result = ""
# DictionaryEntry に展開
for ent in dic:
	result += ent.Key + nn + ent.Value + nn + nn

sr = System.IO.StreamWriter("env.txt")
sr.Write(result)
sr.Close()

なんか Python らしくないコードだ、なんたって値取得に括弧が付いていない。
プロパティから取得する部分には当然括弧は付かないわけでこうなってしまう。
大文字が多いのはしかたがないが CPython コードとの見分けになると思えば…

#! /usr/bin/env python は言うまでもなく書いてはいけません。
つーか *.py は Windows での振り分けにはどうしよう?関連づけは CPython だし。

なんて解説をしているのでもう解ると思うけどこのコードは mono でも動きます。
Ubuntu 8.10 デフォルト状態でも IronPython 1.1.2 ならそのまま動かせる。

linux_ipy

とはいえ Linux で IronPython というのは凄く無駄を感じますけど。
動かせるとはいえ実用となると今後もビミョーとしか言いようがない。

一応書くと Mac は全然解りません。