Hatena::ブログ(Diary)

atsuoishimotoの、もう http://www.gembook.orgに引っ越しちゃったよ日記 このページをアンテナに追加 RSSフィード

引越しのおしらせ

    こちらのはてな日記の内容は、 http://www.gembook.org に 移転しました。

2012-11-29

引越しのおしらせ

こちらのはてな日記の内容は、 http://www.gembook.org に移転しました。

2012-10-24

Pythonで++i

この間、Pythonで変数のインクリメントないよね、って話がでた。こんなのだ。

i = 99
++i
print i

ちなみに、Pythonでも ++i や --i と書くことはできる。書くことはできるが、Pythonでは ++ や -- はインクリメント/デクリメント演算子ではなく、単項の + や - を二つ続けて書いているだけで、こう書いたのと同じ結果になるだけだ。

++i == +(+(i))
--i == -(-(i))

だが、ここで重要なのは、この式はコンパイルエラーにはならないという事実だ。コンパイルエラーにならないということは、すなわち抽象構文木(AST)を作れるということだ。そしてASTを作れるということは、みんな大好きastモジュールで好き勝手できるということなのである。

import ast

class InclTransformer(ast.NodeTransformer):
    def visit_Expr(self, node):
        if isinstance(node.value, ast.UnaryOp):
            if isinstance(node.value.op, ast.UAdd):
                if isinstance(node.value.operand, ast.UnaryOp):
                    if isinstance(node.value.operand.op, ast.UAdd):
                        num = ast.copy_location(ast.Num(n=1), node)
                        n = ast.AugAssign(
                                target=node.value.operand.operand,
                                op=ast.Add(), value=num)
                        return ast.copy_location(n, node)
        return node

s = """
def inc(i):
    ++i
    return i
"""
m = ast.parse(s, "filename", "exec")
exec compile(InclTransformer().visit(m), "filename", "exec") in globals()

print inc(99)

2012-10-02

Python3.3のdecimalが馬鹿っぱやい件

Python 3.3 では decimalモジュールがC言語で実装され、10進浮動少数演算が馬鹿っぱやになりました。

単純なニュートン法で平方根を計算してみると、

def newton(n):
    guess = n/2
    better = (guess + n/guess)/2
    while better != guess:
        guess = better
        better = (guess + n/guess)/2
    return guess

Python2.7では

浮動少数点
$ python -m timeit "import decimal;import newton;newton.newton(2.0)"
100000 loops, best of 3: 2.73 usec per loop
decimal
$ python -m timeit "import decimal;import newton;newton.newton(decimal.Decimal('2.0'))"
1000 loops, best of 3: 649 usec per loop

Python 3.3では

浮動少数点
$ python3 -m timeit "import decimal;import newton;newton.newton(2.0)"
100000 loops, best of 3: 3.56 usec per loop
decimal
$ python3 -m timeit "import decimal;import newton;newton.newton(decimal.Decimal('2.0'))"
100000 loops, best of 3: 13.6 usec per loop

速くなったとは言ってもfloatの数倍はかかってしまうレベルではあるが、それでももともとPythonの浮動小数点演算なんて別に速いというほどのものではない。どっちにしろ遅いんだから、この程度の差なら数値演算が主なスクリプト以外では、全てDecimalで済ませてしまっても問題ないというレベルではないだろうか。

2012-09-21

Pandocでblockdiagを使う

最近、ドキュメント生成ツールとして Pandoc をちょっと試している。Markdownで手軽に書けて、reStructuredTextよりも好みだ。

Pandocというのは「ドキュメント生成ツール」ではなく、正確に言えば「ドキュメント変換ツール」だ。MarkdownからHTMLやPDFへの変換だけでなく、MarkdownからreStructuredTextへの変換や、HTMLからテキストファイルへの変換などもできるようになっている。

そしてその変換のフォーマットとして、Pandocの抽象構文木をそのままJSON形式などでの入出力がサポートされており、この機能を使えばpandoc本体に手を加えずともいろいろな機能を追加できるようになる。ということで、blockdiag を Markdownテキストに記述し、図を生成するフィルターを作成してみた。

このようなMarkdownから、

Example
------------
Following image was generated by blockdiag. 

````blockdiag
{
  世界の -> こ;
  世界の -> み;
  世界の -> か;
}
````

こんな画像が表示される

f:id:atsuoishimoto:20120921192722p:image

ソースはこちら - https://github.com/atsuoishimoto/pandoc-blockdiag-sample

本来はHaskellで書けば、Pandocモジュールを直接使ってもう少しシンプルにかけるが、ここではあえてPythonで書いている。決してHaskellから逃げたのではない、という点をご理解いただければ幸いである。