読者です 読者をやめる 読者になる 読者になる

年金ロボットをめざして

FX(外国為替証拠金取引)自動運用ロボットの開発ブログのはずだった

プログラミング言語ごとの多倍長整数の取り扱い Scala 編

プログラミング言語

現在、ぼくは Haskell のどっぷりハマっている。でも、ちょっと前は Scala に取り組んでいた。なにを隠そう Scala に取り組んだおかげで、Haskell の価値に気付くことができたという次第なのだ。

さてこんかいは以前に書いた「プログラミング言語ごとの多倍長整数の取り扱い」という記事に Scala を追加したい。

Scala多倍長整数演算については Project Euler Problem 20 を例にとって、紹介したいと思う。 Scala 使いにとっては当たり前の事項かもしれないが、ぼくはわからなかったので試行錯誤したのだ。

------------------------------------------
Problem 20 「各位の数字の和 2」
------------------------------------------
n × (n - 1) × ... × 3 × 2 × 1 を n! と表す.

例えば, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800 となる.
この数の各桁の合計は 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27 である.

では, 100! の各位の数字の和を求めよ.

■ 解答 in Scala

//-----------------------------------------------------------------
def fact(n: Int): BigInt = if (n < 2) 1 else n * fact(n - 1)
print(fact(100).toString.split("").map(_.toInt).sum)
//-----------------------------------------------------------------

上の2行が Scala による Problem 20 の解答になっていると思うが、本来は以下のようにできるはずと思っていた。

■ 本来の正解

print((1 to 100).reduce(_*_).toString.split("").map(_.toInt).sum)

↑これで、できると思ったけど、ダメだった。(1 to 10) ならうまく行くけど、(1 to 100) だとオーバーフローしちゃうんだよね。最初の解答のように BigInt を使えばいいと思うけど「本来の正解」でなんとかしたい。だけど、どうしたらいいのかまだわからない。
..ということだった。

Scala REPL で

scala> (BigInt(1) to 100).product.toString.split("").map(_.toInt).sum
res1: Int = 648

それが、上のようにすればできることがわかったのだ。どこで知ったのかって? いろいろやってみたらできた(笑)。

コンパイルソースコード

object PE20 extends APP {
    print((BigInt(1) to 100).product.toString.split("").map(_.toInt).sum)
}

■ ついでに 1000の階乗

scala> (BigInt(1) to 1000).product
res0: BigInt = 4023872600770937735437024339230039857193748642107146325
43799910429938512398629020592044208486969404800479988610197196058631
66687299480855890132382966994459099742450408707375991882362772718873
25197795059509952761208749754624970436014182780946464962910563938874
37886487337119181045825783647849977012476632889835955735432513185323
95846307555740911426241747434934755342864657661166779739666882029120
73791438537195882498081268678383745597317461360853795345242215865932
01928090878297308431392844403281231558611036976801357304216168747609
67587134831202547858932076716913244842623613141250878020800026168315
10273418279777047846358681701643650241536913982812648102130927612448
96359928705114964975419909342221566832572080821333186116811553615836
54698404670897560290095053761647584772842188967...

まぁ、わかってしまえば簡単ということだった。

(1.toBigInt to 100).product などは試していたのだけどね。これが分かるまでちょっと時間がかかってしまった。同じように悩んでいる人のためにと思ったのだけど、まっ、そんな人はいないか。

 

ヒット&ブロー in Python

プログラミング言語

Python 仲間の sin さんが、プログラムを作ったので、許可を得て公開することにした。小さなプログラムだけど、ゲームの桁数を選べるようになっている。この拡張はぼくが行った。人のふんどしで相撲を取るとはこういうことかな。

遊び方は、ヒット&ブローがどういうものか知っていれば、プログラムを実行すればメッセージを出しているのでわかると思う。暇な人がいたら、遊んでみてください。

# ------------------------------------------------------
# ヒット&ブロー プログラム(hitblow.py)
# オリジナル : sin
# アレンジ   : mazin
# ------------------------------------------------------
def makeanswer(length):
    # 異なる(length)桁の数字を作る / 返値は(length)桁の数字配列
    import random
    answer = []
    while len(answer) < length:
        m = str(random.randint(0,9))
        if m not in answer: answer.append(m)
    return answer

def checknum(n, length):
    # 入力された数字のチェック / n は数字文字列
    n = list(n)
    if len(n) != length: return "error length"
    if max([n.count(i) for i in n]) > 1: return "error overlap"
    return True

def jugement(n, answer, length):
    # 入力された数字の判定 / n は入力数字文字列、answer は正解数字配列
    n = list(n)
    hit = 0
    blow = 0
    for x in range(length):
        if n[x] == answer[x]: hit += 1
        elif n[x] in answer: blow += 1
    return [hit, blow]

# ヒット&ブロー メインプログラム
if __name__ == "__main__":

    trial = 1
    while True:
        try:    length = int(input("何桁の数字で遊びますか: "))
        except: print("エラー:不正な入力です"); continue
        if length >= 1 and length <=10: break
        print("エラー:桁数は1桁以上10桁以下です")
        continue

    answer = makeanswer(length)

    while True:
        n = str(input(str(length) + "桁の数字を入力してください " + str(trial) + "回目: "))
        if checknum(n, length) == "error length":
            print("エラー:数字は" + str(length) + "桁です")
            continue
        if checknum(n, length) == "error overlap":
            print("エラー:同じ数字は使えません")
            continue

        hit, blow = jugement(n, answer, length)
        if hit == length:
            print("大正解")
            break
        print(str(hit)+"ヒット" + " " + str(blow)+ "ブロー")

        trial += 1
    print("おめでとうございます! 入力回数は", trial, "回でした。")
# ------------------------------------------------------

(以上)

 

FUNP - 関数型プログラミング

プログラミング言語

また、少しご無沙汰してしまった。

そんなぼくが投稿する気になったのは、渡辺真さんからのコメントをいただいたからだ。実にありがたい。渡辺さんのように一つの言語(FreeBasic)に拘る姿勢には敬意を持ちます。

ぼくの場合は、気が多すぎるのと、自分にとっての理想の言語探しの最中に迷子になってしまっていたようなのだ。そして、迷子のまま歳を取ってしまったという感じ。そんなぼくが漸くにして、迷いから目覚めたように思うのだ。

それがなにかといえば、FUNP(ファンプ)なんだ。OOP とはよく言われるが、FUNP とは言われないようだけど、これ「関数型プログラミング」あるいは「関数型プログラミング言語」のこと。どちらかは文脈で判断する。

FUNP といっても色々あるが、まぁ、とりあえず Haskell かな。1~2年前に Haskell は学んだんだ。もちろん独学。そのとき、理解できたと思った。しかし、ぼくが想定するアプリケーションは入出力が多い。Haskell は不向きだと思った。しかし、それは理解不足に過ぎなかった。

また、Python などに馴染みの深いぼくは、Haskell の「型」への拘りが面倒で不自由なものに感じたんだ。カタカタカタカタとうるせぇよぉってな具合だ。結局、第1次の学習時点では、自分の身の丈に合った言語ではないと判断した。

その後、もっと自由な FUNP を求めて、LispScala を学んだ。そのことで漸く Haskell の価値に気付いたという次第。長い道のりであった。

そしていま、第2次 Haskell 学習がスタートした。もうなんとなく忘れかけていたので、復習からだ。Haskell の第2次が一段落したら、Elm(ウェブ世界の Haskell)と Agda(アグダ)を調べてみようと思っている。いずれにせよ FUNP なのだ。

それと、Haskell が簡潔な言語だということには誰もが賛同してくれると思うが、実は「簡単な言語」でもあるのではないかと近頃では思うようになった。どの書籍も細かなことと過剰な例題が、難しくしているだけなのではないかということ。

もっと大筋と利用する場合の全体像を明瞭に示せるのではないかと思い始めたのだ。勘違いである可能性もあるかな(笑)。それで、自分の学習が終わったら、つぎはそれ(簡単!FUNPってこと)に挑戦しようかと思いつつあるところなのだ。

で、簡単!FUNP のターゲットは、そりゃ、Haskell でしょってことになるけど、まずは Pythonを考えている。これは、Python を完全に FUNP として使ったらどうかというもの。ちょっと調べた感じでは、先行き暗いね(笑)。

というわけで、渡辺さんには、FreeBasic の情報をいただいてうれしいぼくなのだけど、いまは FUNP に夢中ってわけ。簡単!FUNP の成果はいつか何処かで発表したいと思っているけど、いまのところ先は見えていない。

※ こういう技術情報でも何でもないことを書いて、誰がうれしいのかってご批判もあろうけど、自分のために書いているってことで、たまたま見た方はご容赦ください。

 

FreeBASIC の日本語標準入力問題について

プログラミング言語

ちょっと前「I love FreeBASIC」という記事を書いた。誰が無理だってぇ。

f:id:fxrobot:20161009013305j:plain

そこで、FreeBASIC は魅力的な処理系だけど、標準入力からの日本語入力に問題があるという話をした。

そして、その問題に対処する裏技を発見したとも書いた。で、その対処法を書かなかった。誰か突っ込んでくれないかなぁという想いからである。寂しいのである(笑)。

その記事に対し、FreeBASIC の大先生と思しき方から、きみのうんちくを訊いてやろうとお声が掛かった。ぼくはうれしくなって、早速ここに書いている次第なのだ。

と、中身のない話で出だしは十分。で、なんだっけ。

''----------------------------------------------------
Dim s As String
Input "なにかキー入力して下さい: ", s
Print "あなたがキー入力した内容: "; s
Sleep
''----------------------------------------------------

そうそう、FreeBASIC は↑これができない。この s に日本語が入れられない。で、大した方法でもないしけど、ある方法で、うまく行ったのだ。それが↓これ。

''-----------------------------------------
Dim s As String
Open Cons For Input As #1
Print "なにかキー入力して下さい: ";
Input #1, s
Print "あなたがキー入力した内容: "; s
Close
Sleep
''-----------------------------------------

入力装置をオープンして、それに標準入力を割り当てるということ。だだそれだけ。
ひょっとしたらと思ってやってみたら、まぁまぁうまくいったということ。
上のプログラムを実行した結果は以下の通り。

C:\_bas>fbc constes.bas

C:\_bas>constes
なにかキー入力して下さい: こんにちは
あなたがキー入力した内容: こんにちは

C:\_bas>constes
なにかキー入力して下さい: ―ソЫ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿
あなたがキー入力した内容: ―ソЫ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿

C:\_bas>

と、こんな感じで、ちゃんとできてる。
この方法でも完璧というわけじゃないけど、まぁ、動いているね。それでよしっ。

ってことで。
きょうから、FreeBASIC で日本語入力ができるぞっ!

 

Nim 0.15.0 リリース!

と、書けばめでたいようだけど、そうじゃない。
よろこんで、リリース日に早速インストールしたけど、文字化けの嵐だ。

0.15.0 では「Now when you compile console applications for Windows, console output encoding is automatically set to UTF-8.」と、こんなことをしでかしてくれたのだ。

Go や Free Pascal を見習えよ!と言いたい。まぁ、そこまでしてくれなくてもいいから、現状維持で頼むよ。というわけで、0.15.0 は、日本語 Windows じゃ、使えない。あっ、コンソールアプリのことね。仕方ないから 0.14.2 を使うようにしてほしい。

で、Nim のサポートに連絡をしておいたよ。
余計なことをしてくれたなぁ~ってね。

【追伸】
その後、Nim サポートから「Alright, I will see what I can do for you. 0.15.2 is around the corner, fixing installation hassles and regression.」という返信が来た。(変なの)

調子に乗ったぼくは、もし可能なら、Go や Free Pascal の仕事を調べてほしい、彼らの日本語に関する仕事は完ぺきだから、と頼んだ。まっ、無理なんだけどさ。だって、こう言うのが楽だったから。それに言ってやりたかった。

0.15.0 でがっかりしたみんなは、0.15.2 とやらを待とう!

 

Project Euler 4, 5, 6, 8, 13 in Nim

プログラミング言語

ぼくは Nim が好きだ。

一つ前の記事で I Love FreeBASIC とか見たぞ。ああ、それはホント。ぼくはね、FBC(Free Basic Compiler)と FPC(Free Pascal Compiler)それに Nim が好きなコンパイラなんだ。で、こんかいは Nim の件。

f:id:fxrobot:20160929195158p:plainさて、画像の本は、2017年3月3日に発売予定とのことである。(もし)発売したなら買いたいと思っているんだ。でも、どうせ(また)延期になるんじゃないか。

多分、ここに書いてある程度は既にぼくにはわかっているはず。でもね、記念に買いたいと思っているんだ。それに、読んで楽しみたいと思っている。(ちなみに英語は苦手だけどね)

Nim は確かに安定するまでには、まだ時間がかかることだろう。現在のバージョンは 0.14.2 。実際、ぼくはコンパイルでぶっ飛ばしたこともある。

 だけど、Nim は魅力的な言語だ。みんなにも、もっと使ってみてもらいたい。Windowsバイナリのインストーラを提供してくれている(http://nim-lang.org/download.html)ので、ダブルクリックで簡単にインストールできる。コンパイルも簡単だ。

C:\_nim\nim c hello.nim

のようにするだけ。ちなみにぼくの場合、NIm コンパイラ本体は C:\Nim にインストールして、ぼくが書いた Nimのプログラムは C:\_nim に入れている。

プログラムソースファイルは、迷うところだが、現在は Shift-JIS にしている。UTF-8 などにした場合には、DOS窓に日本語を表示するには一々 UTF-8 → Shift-JIS 変換が必要だ。もし、プログラムソースファイルを UTF-8 にする場合は、以下のようにプログラムすれば動くよ。

#-------------------------------------------------------------------------
import encodings

proc tos(u: string): string = convert(u, "shift_jis", "UTF-8")

let hello = tos("こんにちは、世界!")
let kanji = tos("―ソЫ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹")

echo hello
echo kanji
#------------------------------------------------------------------------- 

既に述べたけど、ぼくはプログラムソースファイルを Shift-JIS にしている。その場合はこんな感じ。ほとんどそのままでいいよ。

#-------------------------------------------------------------------------
let hello = "こんにちは、世界!"
let kanji = r"―ソЫ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹"

echo hello
echo kanji
#------------------------------------------------------------------------- 

漢字の文字列に r が付いているのは、RAW文字列として出力している。r を外すとコンパイルエラーになるんだ。このように現在の Nim は「DOS窓+日本語」に関して完全とは言えない。おそらくこれは正式リリースしても変わらないと思う。

そもそも「DOS窓+日本語」に丁寧に対応しているプログラミング言語だと最近思ったのは Go と Free Pascal だけだよ。まぁ、Nim は次点で合格というところか。

ああ、ついでに思い出した。最近のことだけど、Ruby 1.8.7 をインストールしたんだ。そこ、古っとか言わない。で、各種漢字コードには対応していたんだけど。irb を起動して驚いた。まったく日本語が入力できない。これは使い方が悪いのか? 起動オプションとかあるのか? 日本人を想定していないのか? 教えて。

つぎは、もうちょっと参考になるコードを示そう。

Project Euler という素晴らしいプロジェクトがある。https://projecteuler.net/
ぼくがいつも見ているのはこっち → http://odz.sakura.ne.jp/projecteuler/

たくさんある問題から適当に選んで Nim で解いてみた。

Problem 4 「最大の回文積」

左右どちらから読んでも同じ値になる数を回文数という. 2桁の数の積で表される回文数のうち, 最大のものは 9009 = 91 × 99 である.
では, 3桁の数の積で表される回文数の最大値を求めよ.

# pe4
import strutils, unicode
var m, a, b, c: int

m = 0
a = 999
while a > 99:
    b = 999
    while b >= a:
        c = a*b
        if c > m and c.intToStr == c.intToStr.reversed: m = c
        b -= 1
    a -= 1
echo m  #=906609


↑これを見るとわかると思うけど、Nim は Python とそっくりなんだ。ただし、いま思うと、ちょっと違ったとき方をしたいと思う。それらについては他の問題でお目に掛けよう。

Problem 5 「最小の倍数」

2520 は 1 から 10 の数字の全ての整数で割り切れる数字であり, そのような数字の中では最小の値である.
では, 1 から 20 までの整数全てで割り切れる数字の中で最小の正の数はいくらになるか.

# pe5
import future

var n = 20
while true:
    if lc[x | (x <- 1..20, n mod x == 0), int].len == 20: break
    n += 20
echo n  #=232792560


↑この問題では、内包表記を使ってみた。このあと、Project Euler を解きながら、Nim を少しずつ学んで行ったのだった。

Problem 6 「二乗和の差」

最初の10個の自然数について, その二乗の和は, 12 + 22 + ... + 102 = 385

最初の10個の自然数について, その和の二乗は, (1 + 2 + ... + 10)2 = 3025

これらの数の差は 3025 - 385 = 2640 となる.

同様にして, 最初の100個の自然数について二乗の和と和の二乗の差を求めよ.

# pe6
import future, math

echo sum(lc[x | (x <- 1..100), int])^2 - sum(lc[x^2 | (x <- 1..100), int])  #=25164150


↑この解答は Nim の内包表記のテストそのものだ。問題を式にしたら解けていたという感じ。ただ、どの機能がどのモジュールに入っているのかが問題(笑)。

Problem 8 「数字列中の最大の積」

次の1000桁の数字のうち, 隣接する4つの数字の総乗の中で, 最大となる値は, 9 × 9 × 8 × 9 = 5832である.

73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450

この1000桁の数字から13個の連続する数字を取り出して, それらの総乗を計算する. では、それら総乗のうち、最大となる値はいくらか.

EX 6桁の数123789から5個の連続する数字を取り出す場合, 1*2*3*7*8と2*3*7*8*9の二通りとなり, 後者の2*3*7*8*9=3024が最大の総乗となる.

# pe8
const data = """
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450"""

import strutils, sequtils

var max = 0
let str = data.splitLines.join
for x in 0..987:
    let s = toSeq(items(str[x .. x+12]))
    let p = map(s, proc(x: char): int = parseInt($x))
    let q = foldl(p, a*b)
    if max < q: max = q
echo max  #=23514624000


↑この問題を解くことで、Nim の能力が良くわかったのだったと思い出す。

まずは、小さなことのようだけど、

const data = """
73167176531330624919225119674426574742355349194934

と、複数行文字列を定義しているが、Nim では、一番最初にある改行は文字列には含まない。これはなかなか良い配慮で、汚いコードを書かないで済むのはありがたい。

あと、どこかで読んだのだけど、Python の reduce を Guido が「醜い」の一言で却下したと。ここでは、foldl を使っている。Haskell を思い出す。

この辺り、Project Euler の問題を自然に解けるといい気分だった。

Problem 13 「大きな数の足し算」

以下の50桁の数字100個の合計の上から10桁を求めなさい。

37107287533902102798797998220837590246510135740250
46376937677490009712648124896970078050417018260538
74324986199524741059474233309513058123726617309629
91942213363574161572522430563301811072406154908250
23067588207539346171171980310421047513778063246676
89261670696623633820136378418383684178734361726757
28112879812849979408065481931592621691275889832738
44274228917432520321923589422876796487670272189318
47451445736001306439091167216856844588711603153276
70386486105843025439939619828917593665686757934951
62176457141856560629502157223196586755079324193331
64906352462741904929101432445813822663347944758178
92575867718337217661963751590579239728245598838407
58203565325359399008402633568948830189458628227828
80181199384826282014278194139940567587151170094390
35398664372827112653829987240784473053190104293586
86515506006295864861532075273371959191420517255829
71693888707715466499115593487603532921714970056938
54370070576826684624621495650076471787294438377604
53282654108756828443191190634694037855217779295145
36123272525000296071075082563815656710885258350721
45876576172410976447339110607218265236877223636045
17423706905851860660448207621209813287860733969412
81142660418086830619328460811191061556940512689692
51934325451728388641918047049293215058642563049483
62467221648435076201727918039944693004732956340691
15732444386908125794514089057706229429197107928209
55037687525678773091862540744969844508330393682126
18336384825330154686196124348767681297534375946515
80386287592878490201521685554828717201219257766954
78182833757993103614740356856449095527097864797581
16726320100436897842553539920931837441497806860984
48403098129077791799088218795327364475675590848030
87086987551392711854517078544161852424320693150332
59959406895756536782107074926966537676326235447210
69793950679652694742597709739166693763042633987085
41052684708299085211399427365734116182760315001271
65378607361501080857009149939512557028198746004375
35829035317434717326932123578154982629742552737307
94953759765105305946966067683156574377167401875275
88902802571733229619176668713819931811048770190271
25267680276078003013678680992525463401061632866526
36270218540497705585629946580636237993140746255962
24074486908231174977792365466257246923322810917141
91430288197103288597806669760892938638285025333403
34413065578016127815921815005561868836468420090470
23053081172816430487623791969842487255036638784583
11487696932154902810424020138335124462181441773470
63783299490636259666498587618221225225512486764533
67720186971698544312419572409913959008952310058822
95548255300263520781532296796249481641953868218774
76085327132285723110424803456124867697064507995236
37774242535411291684276865538926205024910326572967
23701913275725675285653248258265463092207058596522
29798860272258331913126375147341994889534765745501
18495701454879288984856827726077713721403798879715
38298203783031473527721580348144513491373226651381
34829543829199918180278916522431027392251122869539
40957953066405232632538044100059654939159879593635
29746152185502371307642255121183693803580388584903
41698116222072977186158236678424689157993532961922
62467957194401269043877107275048102390895523597457
23189706772547915061505504953922979530901129967519
86188088225875314529584099251203829009407770775672
11306739708304724483816533873502340845647058077308
82959174767140363198008187129011875491310547126581
97623331044818386269515456334926366572897563400500
42846280183517070527831839425882145521227251250327
55121603546981200581762165212827652751691296897789
32238195734329339946437501907836945765883352399886
75506164965184775180738168837861091527357929701337
62177842752192623401942399639168044983993173312731
32924185707147349566916674687634660915035914677504
99518671430235219628894890102423325116913619626622
73267460800591547471830798392868535206946944540724
76841822524674417161514036427982273348055556214818
97142617910342598647204516893989422179826088076852
87783646182799346313767754307809363333018982642090
10848802521674670883215120185883543223812876952786
71329612474782464538636993009049310363619763878039
62184073572399794223406235393808339651327408011116
66627891981488087797941876876144230030984490851411
60661826293682836764744779239180335110989069790714
85786944089552990653640447425576083659976645795096
66024396409905389607120198219976047599490197230297
64913982680032973156037120041377903785566085089252
16730939319872750275468906903707539413042652315011
94809377245048795150954100921645863754710598436791
78639167021187492431995700641917969777599028300699
15368713711936614952811305876380278410754449733078
40789923115535562561142322423255033685442488917353
44889911501440648020369068063960672322193204149535
41503128880339536053299340368006977710650566631954
81234880673210146739058568557934581403627822703280
82616570773948327592232845941706525094512325230608
22918802058777319719839450180888072429661980811197
77158542502016545090413245809786882778948721859617
72107838435069186155435662884062257473692284509516
20849603980134001723930671666823555245252804609722
53503534226472524250874054075591789781264330331690

↑これは問題に現れる数字が実にデカイっていうか多い。それで解きたくなって #13 まで飛んだ次第。ごめん。↓もう一度プログラムのなかに現れるよ。

# pe13
const data = """
37107287533902102798797998220837590246510135740250
46376937677490009712648124896970078050417018260538
74324986199524741059474233309513058123726617309629
91942213363574161572522430563301811072406154908250
23067588207539346171171980310421047513778063246676
89261670696623633820136378418383684178734361726757
28112879812849979408065481931592621691275889832738
44274228917432520321923589422876796487670272189318
47451445736001306439091167216856844588711603153276
70386486105843025439939619828917593665686757934951
62176457141856560629502157223196586755079324193331
64906352462741904929101432445813822663347944758178
92575867718337217661963751590579239728245598838407
58203565325359399008402633568948830189458628227828
80181199384826282014278194139940567587151170094390
35398664372827112653829987240784473053190104293586
86515506006295864861532075273371959191420517255829
71693888707715466499115593487603532921714970056938
54370070576826684624621495650076471787294438377604
53282654108756828443191190634694037855217779295145
36123272525000296071075082563815656710885258350721
45876576172410976447339110607218265236877223636045
17423706905851860660448207621209813287860733969412
81142660418086830619328460811191061556940512689692
51934325451728388641918047049293215058642563049483
62467221648435076201727918039944693004732956340691
15732444386908125794514089057706229429197107928209
55037687525678773091862540744969844508330393682126
18336384825330154686196124348767681297534375946515
80386287592878490201521685554828717201219257766954
78182833757993103614740356856449095527097864797581
16726320100436897842553539920931837441497806860984
48403098129077791799088218795327364475675590848030
87086987551392711854517078544161852424320693150332
59959406895756536782107074926966537676326235447210
69793950679652694742597709739166693763042633987085
41052684708299085211399427365734116182760315001271
65378607361501080857009149939512557028198746004375
35829035317434717326932123578154982629742552737307
94953759765105305946966067683156574377167401875275
88902802571733229619176668713819931811048770190271
25267680276078003013678680992525463401061632866526
36270218540497705585629946580636237993140746255962
24074486908231174977792365466257246923322810917141
91430288197103288597806669760892938638285025333403
34413065578016127815921815005561868836468420090470
23053081172816430487623791969842487255036638784583
11487696932154902810424020138335124462181441773470
63783299490636259666498587618221225225512486764533
67720186971698544312419572409913959008952310058822
95548255300263520781532296796249481641953868218774
76085327132285723110424803456124867697064507995236
37774242535411291684276865538926205024910326572967
23701913275725675285653248258265463092207058596522
29798860272258331913126375147341994889534765745501
18495701454879288984856827726077713721403798879715
38298203783031473527721580348144513491373226651381
34829543829199918180278916522431027392251122869539
40957953066405232632538044100059654939159879593635
29746152185502371307642255121183693803580388584903
41698116222072977186158236678424689157993532961922
62467957194401269043877107275048102390895523597457
23189706772547915061505504953922979530901129967519
86188088225875314529584099251203829009407770775672
11306739708304724483816533873502340845647058077308
82959174767140363198008187129011875491310547126581
97623331044818386269515456334926366572897563400500
42846280183517070527831839425882145521227251250327
55121603546981200581762165212827652751691296897789
32238195734329339946437501907836945765883352399886
75506164965184775180738168837861091527357929701337
62177842752192623401942399639168044983993173312731
32924185707147349566916674687634660915035914677504
99518671430235219628894890102423325116913619626622
73267460800591547471830798392868535206946944540724
76841822524674417161514036427982273348055556214818
97142617910342598647204516893989422179826088076852
87783646182799346313767754307809363333018982642090
10848802521674670883215120185883543223812876952786
71329612474782464538636993009049310363619763878039
62184073572399794223406235393808339651327408011116
66627891981488087797941876876144230030984490851411
60661826293682836764744779239180335110989069790714
85786944089552990653640447425576083659976645795096
66024396409905389607120198219976047599490197230297
64913982680032973156037120041377903785566085089252
16730939319872750275468906903707539413042652315011
94809377245048795150954100921645863754710598436791
78639167021187492431995700641917969777599028300699
15368713711936614952811305876380278410754449733078
40789923115535562561142322423255033685442488917353
44889911501440648020369068063960672322193204149535
41503128880339536053299340368006977710650566631954
81234880673210146739058568557934581403627822703280
82616570773948327592232845941706525094512325230608
22918802058777319719839450180888072429661980811197
77158542502016545090413245809786882778948721859617
72107838435069186155435662884062257473692284509516
20849603980134001723930671666823555245252804609722
53503534226472524250874054075591789781264330331690"""

import strutils, bigints

var total = 0.initBigInt
let seqNum = data.splitLines
for x in seqNum: total += x.initBigInt
echo toString(total)[0..9]  #=5537376230


↑悪いね。意味もなく行数を取って。ただ、プログラムソースのなかにデータをこんなふうに書けることを示したかった。Haskell ではこうはいかない。別ファイルで読み込む一手だろう。あるいは、プライドを棄てて作業をするかだね。Haskeller にはそれは出来ない相談だろう。

さて、この問題は、bigints モジュールを使っているんだ。それを試したくて解いてみたんだ。見ての通り、bigints では x.initBigInt で「文字列 → 整数」に toString(x) で「整数 → 文字列」にするってのがポイントだと思う。それさえ押さえれば使えると思う。

こんなに簡単に解けるのは凄いと自画自賛。
これがぼくが Nim を好きな理由の一つなんだ。

 

I love FreeBASIC

プログラミング言語

Love なんて気持ち悪いよ!

う、うん、確かにね。でもね、そう言いたくなるくらい魅力的な処理系なのだ。
まぁ、構文が Basic な C言語だって意見もあるけどね。

f:id:fxrobot:20160921162102p:plain思い起こせば、ぼくが FreeBASIC に興味を持ったのは、バージョンがまだ 0.xx の時代だった。そしていまは、1.05 になった。知らないうちに正式バージョンになったんだね。

ところで、最近のことだけど、ぼくは Go、D、Nim、Free Pascal、FreeBASIC という 5つのコンパイラWindows の日本語環境で比較したんだ。その結果、信頼できるコンパイラは Go と Free Pascal であることがわかった。

FreeBASIC の話はどうなったんだ! うん、そう、love な FreeBASIC には、残念ながら基本的で致命的な日本語に関するバグがあったんだ。それはこんな簡単なプログラムで起こる。

''----------------------------------------------------
Dim s As String
Input "なにかキー入力して下さい: ", s
Print "あなたがキー入力した内容: "; s
Sleep
''----------------------------------------------------

このプログラムを実行すると、

なにかキー入力して下さい:                          ← 入力した文字は消える
あなたがキー入力した内容: bbbbb        ← 文字化けして表示される

そう、標準入力からの日本語入力で起きちゃうんだ。日本語を入力して、日本語を出力する基本だよね。なお、日本語の出力にはなにも問題ない。

ぼくはこれを見て「使えねぇ」ということになった。Love なのにだ。インサートできなければ愛も消える。(下ネタなの?)

ところがだね。ところがだ。ぼくは裏技を発見したのだ。..裏技って ..

日本語をインサートできるのだ。これで愛も復活だ。
つづく ...

えっ。

もしかしたら、インサートって言いたかっただけとか。
いえ、いえ、ご希望があれば、次号にて。

 

プログラミング言語ごとの多倍長整数の取り扱い

プログラミング言語

ぼくにはプログラミング言語に求める基本的な機能がある。

f:id:fxrobot:20160921134655p:plain

その一つが多倍長整数(演算)である。だから、基本的には多倍長整数族の言語が好きなのだ。多倍長整数が当たり前ってのが、とくにね。Common Lisp とか Python とかね。好きだね。そもそもこれが言語機能に存在しないプログラミング言語というものはひ弱に思われる。もっとも多倍長整数なんて必要ないという人が多数派だよね。わかってる。でも、やっぱり、多倍長整数ができないってのはね ..。

そこでこんかいは、Julia、Go、D、Rust、Nim、Free Pascal、FreeBASIC のそれぞれでで多倍長整数がどうなっているのか調べてみよう。

まず Julia だけど、これはいい言語だね。Julia については語りたいことは多いけど、こんかいは多倍長整数がテーマだ。さて、Julia には factorial という組込関数がある。まずはそれを試してみよう。

f:id:fxrobot:20160921130421p:plain

factorial(100) でオーバーフローだ。そこでこれだ。

julia> factorial(big(100))
9332621544394415268169923885626670049071596826438162146859296389521759
9993229915608941463976156518286253697920827223758251185210916864000000
000000000000000000

無事計算できたぞ。以下、factorial(big(1000)) も同様にうまく行く。
もし、独自に関数をつくって多倍長整数に対応させたければ、以下のようにすればよい。

function fact(n)
    if n == 0
        big(1)
    else
        n * fact(n - 1)
    end
end

そして fact(1000) とすればよい。Python に近い使い心地だけど、やはり、ちょっとだけだけど工夫が必要なんだ。ぼくは気付かなかったけど、使う人によっては Python とは雲泥の差と感じるようなんだ。

f:id:fxrobot:20160921141339p:plain

じゃ、つぎは Go だ。

Go はぼくにとって最も信頼できるコンパイラ言語の一つなんだ。ただ、それでもね、矛盾するようだが、あまり使う気にならないだよなぁ。多倍長整数の仕様もその理由の一つだね。

だけど、Go の信頼できるスタンドアロンの exe は使わなきゃもったいない。それに、ぼくはこういうシンプルな言語を求めていたはずなんだ。それがねぇ。

で、Go の場合の多倍長整数は import "math/big" で準備OK。以下のプログラムはずいぶん前にぼくが作ったものだが、動いたかなぁ(笑)。しーらないっと。でも、多倍長整数の使い方はわかるよね。しかし、それにしても何でこんな仕様かというと、その原因は GNU Multiple Precision Arithmetic Library にあるのだろう。それと、Go はオーバーロードができないということか。それで、こんなに醜くなってしまうとしたら、やっぱり必要な機能なんだね。

 package main
import (
    "fmt"
    "strconv"
    "math/big"
)
func isPrime(n *big.Int) bool{
    isPrime := n.ProbablyPrime(50)  // 20 で十分かも
    return isPrime
}
func main() {
    var s string
    fmt.Print("メルセンヌ数素数判定する n を入力せよ(2^n - 1): ")
    fmt.Scanln(&s)
    m, _ := strconv.ParseInt(s, 10, 64)
    one := big.NewInt(1)
    two := big.NewInt(2)
    mer := big.NewInt(m)
    n := new(big.Int).Exp(two, mer, nil)
    n.Sub(n, one)
    fmt.Println(n)
    fmt.Println("素数: ", isPrime(n))
}

↑この仕様を見る限り使う気にはならないんだけどね。でも、何はともあれ、コンパイラ言語が標準で多倍長整数が使えるのは魅力だね。

f:id:fxrobot:20160921143647p:plain

つぎ、D言語行ってみよう。

D はぼくのお気に入り言語の一つだ。

でもね、それなのにぃ、D は日本語入りソースは utf-8 じゃないとコンパイルエラーだ。で、utf-8 にする。それなのに、DOS窓では日本語が文字化けしちゃうんだ。もちろん文字変換をすればいいだけの話ではあるんだけどね。

多倍長整数の話だったけど、話が出たついでに、ぼくが何を文句を言ってるかってこと。困っている人がいたら以下のようにすればいいよ。(なぜ、"表計算" なのかはわかる人にはわかるよね)

import std.stdio;
import std.file;
import std.string;
import std.conv;
import std.windows.charset;
string tosjis(string u){return to!(string)(toMBSz(u));}
string toutf8(string s){return fromMBSz(toStringz(cast(char[])s));}

void main(){
    string utf8 = "あいうえお"; // UTF8
    writeln("utf8 : ", utf8);
    // UTF8 を Shift-JIS に
    writeln("utf8 to sjis : ", tosjis(utf8));
    writeln(tosjis("表計算するぞぉ!"));

    auto sjis = File("sjis.txt").readln;  // あいうえお をS-JISで保存したファイル
    writeln("sjis : ", sjis);
    // Shift-JIS を UTF8 に
    writeln("sjis to utf8 : ", toutf8(sjis));
    writeln(tosjis("表計算するぞぉ!"));
}

さて、話を戻して、D の多倍長整数。うん、それが、なかなかいいんだよ。まぁ、我慢できるよ。これなら使う気になるよね。

import std.stdio;
import std.bigint;
void main()
{
    BigInt a = "23456789012345678901234567890";
    BigInt b = "742072812345678901234567890";
    auto c = a * b;
    writeln(c);
    BigInt p = BigInt(2) ^^ 742072 - 1;
    writeln(p);
}

f:id:fxrobot:20160921150334p:plain

つぎは Rust だ。手短に行こう。
なぜって、ぼくは Rust が好きじゃない。

じゃ、取り上げなきゃいいだろう。まぁ、いい。で、案の上だ。
いろんな仕組みがある言語なのに、で、多倍長整数をやらせたらこのていたらくだ。(Go と変わんない気がするけど ..)

 

use num::{BigUint, Zero, One};
use std::mem::replace;
fn fib(n: usize) -> BigUint {
    let mut f0: BigUint = Zero::zero();
    let mut f1: BigUint = One::one();
    for _ in 0..n {
        let f2 = f0 + &f1;
        f0 = replace(&mut f1, f2);
    }
    f0
}
println!("fib(1000) = {}", fib(1000));

 前にも書いたと思うけど、Rust は学習シームレスからはほど遠い言語。この変態言語め! いやいや、まじんくん、まちたまえ。将来有望といわれている言語だ。きみが気に入らないからって、そんな言い方はないだろう。

f:id:fxrobot:20160921151459p:plain

気を取り直して、わが愛する Nim に行きましょう。

こんかい紹介する言語の中でぼくが一番好きなのが、この Nim なんだ。確かにね、コンパイルでぶっ飛んだこともあるけどね。それでも、ぼくは Nim が好き。

まぁ、趣味の人だからそう言えるのだろう。職業プログラマなら、まだ、Nim は使えないだろう。それはわかるよ。

で、まずは Nim の日本語処理の話から。

 Nim の日本語を含むソースコードは uft-8 で保存するのがいいのか、shift-jis がいいのか。まぁ、厳密に言えば、uft-8 なんだろうけど、すると、DOS窓に日本語を出すときには shift-jis にコード変換をしなければならない。うん、それで問題ない。ただ、気分がよくない。気分がよくないと言っても↓この程度なんだけどね。

f:id:fxrobot:20160921155102p:plain
ソースコードが、utf-8 の場合だとこんな感じになる)

で、取りあえずぼくは、ソースは shift-jis で保存している。その場合は、ある種の漢字の場合に限っては DOS窓で文字化けする。ここで、ある種の漢字とは「―ソЫ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹觸軆鐔饅鷭」のこと。このなかには、みんなもよく使う「表計算」の「表」が入っているね。

で、RAW文字列の r"―ソЫ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹觸軆鐔饅鷭" で出力すれば問題なし。ただし、内部で utf-8 用関数で文字列処理をする場合はあらかじめ uft-8 に変換する必要があるよね。

 おっと、多倍長整数がテーマだってことをすっかり忘れていたよ。

Nim の多倍長整数はわかりやすい。以下のコードのなかの 1234567890 は通常の整数の範囲なので、1234567890.initBigInt としているが、もっと数字の桁が多い場合は、"12345678901234567890".initBigInt などとすること。あるいは、常に文字列で与えてもいいよね。

#--------------------------------------
import bigints
var i = 1234567890.initBigInt
while true:
    i *= 1234567890
    echo i
    if i.toString.len > 100: break
#--------------------------------------

 上のプログラムを走らせた結果は以下の通り。

C:\_nim>bigint
1524157875019052100
1881676371789154860897069000
2323057227982592441500937982514410000
2867971860299718107233761438093672048294900000
3540705968149597751242378595390670323015412790761000000
4371241896208856100100048221092623586370756606568819264290000000
5396594884482166474814145321212573795589977741475227338905857648100000000
6662462759719942007440037531362779472290810125440036903063319585255179509000000000
8225262591471025795047611436615355477641378922955141680937016996764162077997366010000000000
10154645082248316311927502100842088153631659353603201829685466296589268404251223580523418900000000000

うーん、素晴らしい! 簡単簡単。

f:id:fxrobot:20160921160137p:plain

さて、つぎは FreePascal だ。
Free Pascal多倍長整数をするにはいろんな方法があるようだけど、Free Pascal では、GNU Multiple Precision Arithmetic Library の gmp をオフィシャルなライブラリとして採用しているようだ。
その使用例は以下の通りなのだが、ああ、なんじゃこりゃ。でも、Go や Rust よりはいいと思う。

program gmptest;
{$mode objfpc}
uses gmp;
var
    p, q : mpz_t;
    i : integer;
begin
    mpz_init_set_si(p, 1);
    mpz_init_set_si(q, 1);
    for i := 1 to 100 do
        begin
            p := p * i;
            q := q * 2;
        end;
    p := p + q;
    mp_printf('%Zd', [@p]);
end. 

上のプログラムをコンパイルして、実行した結果は以下の通り。

C:\_pp>fpc gmptest.pp
Free Pascal Compiler version 3.0.0 [2015/11/16] for i386
Copyright (c) 1993-2015 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling gmptest.pp
Linking gmptest.exe
16 lines compiled, 1.6 sec, 66432 bytes code, 4100 bytes data

C:\_pp>gmptest
933262154439441526816992388562667004907159682643816214685929638952
175999932299156089414639761565182862536979208272237582511852121845
14600228229401496703205376

f:id:fxrobot:20160921162102p:plain


さぁ、こんかいの大トリは FreeBASIC だ。

気付いてみれば、FreeBASIC のバージョンが 1.05.0 になっていた。以前触っていたころは、0.xx だったと思ったが。さてさて、Basic 野郎のぼくとしては、どうしたって、FreeBASIC なんだ。うん、なにが?

ぼくから見ると FreeBASIC は Basic の皮を被った C言語といった感じ。ぼくの好きなプログラミング言語の一つなんだ。

また、ちょっとした試していないから断言はできないけど、この多倍長整数ライブラリは、とても自然で使いやすい。これだったら、仕様面では Python と遜色ないだろう。

''---------------------------------------------------------
#Include "lib/big_integer.bas"
Dim as Bigint a, b
a = "123456789012345678901234567890"
b = "12345678901234567890"
Do
    a = a * b
    print a
Loop Until Len(Str(a))>100
Sleep
''---------------------------------------------------------

いつものテストプログラムを書いてみた。上のプログラムを実行してみよう。

C:\_bas>fbc bigint.bas

C:\_bas>bigint
+1524157875323883675034293577501905199875019052100
+18816763723536577725090825131463319235514383922198701224860897069000
+232305722891181533285658896508982806450763702875773153342648107111742077337982514410000
+2867971861733704037699097396383673365184800604885499673956725400135253627043136307363852838672048294900000

 

まぁ、どの言語だって使用するライブラリによるだろうけど、こんかいの例では FreeBASIC の多倍長整数が一番使いやすかったように思う。

なお、一番最初に出てきた顔の画像は、Free Pascal 用の統合環境 Lazarus のロゴだ。気になった人のために。

【Lazarus】http://www.lazarus-ide.org/

f:id:fxrobot:20160921171119j:plain

 実は先日、Delphi 7 を Windows8.1PC にインストしようとしたら互換性がないと怒られた。そこで、Dephi の代わりに Lazarus をインスト。

これ、素晴らしいよ!

 

やさしいプログラミング言語

プログラミング言語

正直に言って、ぼくは古い人間だ。Basic、Pascal の世代なんだ。

ぼくが職業プログラマだった時代は 3年ほどで、アセンブラを使っていた。そして、ぼくが最近学んだ言語は、JavaSchemePythonHaskell なんだ。つい最近は、Go、D、Nim、Rust、Julia それに Common Lisp に興味を持っている。プログラミング言語というものは、それ自体が面白い。

まぁ、ぼくのようなプログラミング言語愛好者にとっては、言語が複雑でもそれほど苦にはならない。しかし、その昔の Pascal のようにシンプルなものはなくなってしまったと言ってよいだろう。残念なことだ。

それにネットを調べれば、出てくるのは Linux 使いの記事ばかり。世間で最も多いのは Windows だって言うのにね。それにね、日本人が作った Gauche という Scheme 処理系が人気なようだが、これって Windows(の DOS窓)に日本語が表示できない。ふざけんなって言いたいのはぼくだけだろうか。もちろん、不可能ってことじゃないだろう。

これについては D などもそうだ。D で、DOS窓に日本語を表示するためには Shift_JIS に変換すればいい。これって、コンパイラ言語だということで、どうにか理解できるけどね。でもね、Gauche のことだけど、Scheme を学びたい多くの学習者(それは Windows ということだ)に日本語は表示できません。Linux を前提としているから、あしからずってことなのだろうか。

最大多数の利用者(Windows 野郎ってこと)を馬鹿にすんな!
ってのは言い過ぎだろうか。

その点においては Go はよくできている。それに Go はシンプルで書きやすい。その言語の哲学が全体に染み渡っている。いまやこの業界全体に行き渡っている C++ 方式の書式にも反抗している。よくやってくれたものだと思う。しかしね、Go はコードが見やすいとは言えない。

Go は C++ に辟易した職業プログラマへの救いであり、シンプルだからやさしいってわけじゃないと思うんだ。プロフェッショナルな言語だと思う。だから、その意味で面白味がない。

ぼくは Go があれば大抵のことは書けそうだ。ありがたい存在だと思う。だけど、これからプログラミング言語を学びたいという人たちにはお勧めできない。

じゃ、いま、そういった人たちにお勧めできるプログラミング言語とはどれだろう。

まぁ、Python ならすべての点において妥当だろう。プログラミング言語をこれから学びたい人には Python(か Scheme)を勧めるのが間違いないだろう(Scheme はちょっと大変だろうか)。

とくに Python はやさしいことは簡単にできる。難しいことだって機能が揃っている。これを「学習シームレス」と呼ぶことにしよう。その使用者のレベルに応じて、そのやさしさ、難しさの顔を変えるということだ。

Go は、学習シームレスな言語とは言えないように思う。

Julia は、学習シームレスな言語だと言えると思う。Julia を知ってしまうと Python がくすんで見えてしまう。Julia の初級者向けの優れた日本語書籍が出れば、これほど覚えやすいプログラミング言語はないだろう。

それに現代のプログラミング言語だけあって、その全体はとても現代的だ。だが、初級者にそれを見せる必要はない。必要なときが来れば、そのときに覚えればよいだろう。

ぼくがもう一つ注目したのが、Nim なんだ。
Nim も学習シームレスなプログラミング言語だと思う。

現時点では(あるいはひょっとしたら将来的にも)品質的な不安があるようだ。しかし、ぼくがちょっとだけど使ってみた印象では、とても魅力的だ。

個人的に Nim のシンタックスに惹かれるという面もあるのだろう。

最後に Rust に触れよう。Rust はとてもじゃないけど学習シームレスとは言えないね。Rust はどんな人が使うのだろう。それは ScalaHaskell を使う人とかぶるのだろうか。いや、それよりは C++ 寄りなのだろう。Java に対する ScalaC++ に対する Rust という関係なのだろう。いずれにせよ、職業プログラマの世界だね。

ぼくは、プログラミング言語というものは、学習シームレスであるべきだと思うんだ。よく Java はやさしいといわれるけど、 Java は学習シームレスじゃない。なぜ、Python のようにできないんだろう。

さて、ぼくが推奨する学習シームレスなやさしいプログラミング言語を挙げてこんかいは終わりにしよう。

それは Python、Julia、Nim の 3つだけど、Nim は仕様と品質の安定、それに、DOS窓への日本語の表示が文字コードの変換なしに可能になることが条件。

Julia は現在、日本語の書籍がまだ出ていない。しかし、その実行速度はコンパイラ言語並だし、言語仕様も美しい。そして、学習シームレスな言語だ。知らない人がいたら、ぜひ、一度使ってみてもらいたい。

Julia は素晴らしいプログラミング言語だと思う。

 

1並び素数の不思議

哲学・芸術・数学・的な

素数というのは不思議なもので、知的好奇心を大いに刺激するものだ。

さて、ぼくはある時期、素数に凝って、そして素数に魅了された。素数のためにゼータ関数類体論なども入り口レベルだけど学んだものだった。

で、こんかいは面白い素数を一つ紹介しようと思う。

1が並んだ数字に素数はあるのか、あるのならどのように分布しているのか。1 は定義上除外しよう。11 は素数だね。じゃ、そのつぎを知っているだろうか。これだ。

1111111111111111111 (1 が 19個)

エヘン、知ってたかい。自慢してどうする。実はこれを知っている人がいたんだ。でも、そのつぎは知らないだろうな。もったいぶるなよ。はい、つぎの通り。

f:id:fxrobot:20160621115040j:plain


これは数学の教科書から取ってきたデータではないので、間違っている可能性があることを留意してほしい。これはぼくが、PARI/GP、PythonHaskell を使い計算した結果なのだ(素数に関してはこの 3言語を利用している)。2万桁以上も検証したが、どこまでしたのか記憶にない。まぁ、力仕事をしただけってことだけど、プログラムを走らせているときはロマンを感じたものだ。

そんなのとっくに数学的に証明されてるよっていう人がいたら教えてほしい。

ついでにもう一つ、エッフェル素数(ぼくが勝手に命名)というものを紹介しよう。

f:id:fxrobot:20160621115209j:plain

定義を書くのはめんどい。見たらわかると思う。あるいは想像して楽しんで。

で、これになんの意味があるって。ごめん、とくに意味はないんだ(笑)。実は、意味のある研究もしたのだけど、いまのところ成果は出ていない。

法則性に関し、ぼく的にはいい線行きそうだってのもあったけど、トコトン突き詰める根性が不足しているんだね、ぼくには。で、まぁ、数字遊びに熱中しただけだったってことだね。

実は、素数に関してはこれ以外に多くの仕事(力仕事&法則妄想)をしたんだけど..気が向いたらまた書くかもしれない。

 

Deep Learning FX

FX・株・金融工学

「Deep Learning FX」いつかこんなタイトルの本がパンローリング辺りから出そうだね。

ぼくも遅ればせながら Deep Learning(深層学習)の勉強を始めたよ。まずは概要を把握しようと「初めてのディープラーニング」という本を読んでいる。アマゾンの書評を見たら、立ち読みで十分な本と書いてあった(笑)。まぁ、ぼくもそんな感じは受けたが、いかに簡単な本でも、ぼくには立ち読みで読み切る根性はない。座っても無理(笑)。

f:id:fxrobot:20160619175842p:plain

で、まぁ、プログラマなぼくとしては Deep Learning FX といえるようなものをできることなら作ってみたいと思いついた。開発は、Python によいライブラリが現れれば Python で書くし、Haskell に現れれば Haskell で書く。Java でもよい。他力本願だ。自分で一からってのは想定していない。そういう状況をウォッチしながら、基礎的な学習を進めるつもり。長丁場になるね。

きょう思いついたので、きょうの日付で書いておきたかった。偶然読んだ方には内容がなくて申し訳ない。

じゃ、この件についてはまたいつか。

 

Deep Learning

FX・株・金融工学

Deep Mind 社(Google)が開発した AlphaGo がトップクラスの囲碁棋士(韓国)に4勝1敗で勝利したことは記憶に新しい。この AphaGo は囲碁の定石などのロジックを組み込んだものではなく、Deep Learing という汎用のメカニズムを利用しているとのことだ。

f:id:fxrobot:20160615223549j:plain

上の画像は Deep Learning によってブロック崩しをやらせた例で、最初に得点を増やすという目的のみを与える。すると最初はボールを弾くことさえできず放置状態。それが偶然にボールを弾き得点が得られると、弾くことを覚える。

そして4時間後には、崩した一角からボールを裏側に回し、高得点を得るテクニックまでを覚えた。これはゲームとのインターフェースを別にするとそのメカニズムは汎用的なものだ。

AlphaGo では過去行われた15万局の棋譜を画像として与えたそうだ。そして勝つときのパターンを学習させた。つぎにある程度強くなった段階からは、AlphaGo 同士を対局させて勝つ方法を学ばせたのである。その数たるや驚きの 3000万局とのことだ。

Deep Learning 自体、とても興味深い話題だが、さて、ここからが本題。

Deep Learning 能力を持った FX の AI トレーダーに過去の大量データから勝ちパターンを学ばせ最強のトレーダーに育ててからトレーディングをさせたらどうなるだろう。まぁ、これは誰もが考えつくことだ。

今後、多くの AI(プログラム)の FX 市場への参入によって相場の状況が変わったとしても Deep Learning はそれにどう対処すべきかを学んでいくだろう。その場合、多くの FX ロボット(MQL 4/5 プログラムなど)はプログラム自体の変更を余儀なくされるはずだ。

まぁ、ぼくが言いたいことは、われわれの幾分古くさい FXロボット開発においても、固定的なロジックばかりではなく、最新の相場データを(リアルタイムでなくとも)常に分析させる方法論が必要になるのだろうということだ。

Deep Learning という汎用のメカニズムは Google が持ってる。さりとて我々だって、対象を FX に限定すれば似たようなアプローチは可能ではないだろうか。

 

チェス用語のカタカナ表記の件

チェス

ルックってなんだよぉ。

昨年の11月にチェスの勉強を始めてから、あれこれチェス本(チェスの教本や問題集のこと)を読んでいる。すると Rook のことを「ルック」と表記する本があった。あれっ、Rook は「ルーク」じゃなかったのか。ぼくはそれがとても気になった。

もちろんルックと書く趣旨はわからなくはない。発音がルックのほうがましと考えたのだろう。でもそれなら Queen をなぜ「クイン」としないのか。「クイーン」だよね。発音としてはクインのほうがかなりましだと思うけどね。でもクイーンは日本語だからクインなんて勝手に変えちゃいけないよね。

これはぼくの場合だが、たとえば Bxc4 という棋譜を読む場合、Bishop takes c four と読んでいる。できる限り英語の発音に近い音にしているつもりだ。ビショップ・テイク・シー・ヨン(フォーでもフォアでもなく四)と日本語として読むことにしている人もいるそうだ。ただ、これは用語問題とは無関係なこと。好みでよいと思う。

えっと、ところで、ぼくは日本語のチェス本をほとんどすべて持っている(えっ、誰がバカだって・笑)。そのほとんどがルークでルックは少数派なのだ。ぼくは、ルークは Rook を示す日本語(カタカナ語)だと思っている。どうして急にルックが出てくるのだろう。英語かぶれなのか?外人と話すのなら【rˈʊk】と発音すればよい。カタカナならルックよりもゥロークのほうが近いだろう。じゃ、ロークか。

つまり日本語「ルーク」をそう簡単に壊さないでほしいと言いたいのだ。チェスがいくら日本でマイナーであるとしても、むしろそれだからこそ、チェス用語の日本語化が大切だと思うし、固定化・安定化が求められるところだ。ルックと書く著者はチェスは所詮英語の世界だと考えているのだろうか。

ところで、マルチプランという表計算ソフトウェアを知っているだろうか。これは日本語として固定されており、誰もがマルチプランと書く。だけど、米国人に口頭で伝えたければ「モーティプラン」(無理にカタカナで書けば)と言うだろう。書くなら、Multiplan だ。

チェスの日本国内での普及を考えるのなら、少なくとも初級・中級くらいまでは日本語だけでチェスが完結する世界が必要であり、重要だと思うのだ。

もうルックとなんて書かないでぇ。英語かぶれ屋さんのイケずぅ。

 

盤上のポラリス

チェス

じつに久しぶりにコミック本を買った。「盤上のポラリス」というチェスを題材にしたコミックだ。これを読んでいてふと思ったことがある。

f:id:fxrobot:20151226103508j:plain

日本でチェスをやる人って..どんな人なんだって。

なぜ、将棋じゃないんだ。日本はチェス弱小国。そりゃ、なんてたって将棋があるからね。

日本におけるチェスとは日本におけるキリスト教のような立ち位置じゃないだろうか。

日本におけるキリスト教徒の割合は僅か1.5%程度と聞く。戦争に負けた日本がよくもキリスト教に浸食されなかったものだと思う。

そこから、こんごも将棋がチェスに侵食されることはないだろうというアナロジーが浮かぶ。

ところで、日本国内でチェスに取り組む日本人に、ぼくはなにやら嫌らしいものを感じていたのだ。偏見だと非難されようが仕方がない。

頭脳ゲームに興味を持つような人ならチェスよりも将棋を先に知るはずだし、チェスに目を向けるような人なら、その前に将棋を知っていたはずだ。

なにが言いたいのだね、まじんくん。チェスを嫌っているのか? いやね、じつはぼくは今年の11月からチェスを学び始めたのだ。チェスは嫌いじゃないよ。むしろね、大好きになりそうなのだ。

今回の記事では、将棋をパスしてチェスに取り組むひとたちの人間像をあれこれ書きたく思っていたのだけど、やはりそれはやめておこう。趣味が悪そうだ。

さて、日本はチェス弱小国だけど、そんな日本国内でチェスのトップクラスになりたければ、英語によるチェス本を読む必要があると思う。

f:id:fxrobot:20151226111614j:plain

近年は、日本語によるチェス本も充実してきているようではあるが、英語本にはまる一冊キングズギャンビット(チェスの定跡の一つ。将棋でいえばまる一冊「横歩取り」だろうか)という分厚い本(全680ページ)もある。

向こうのやつらはこんなの読んでるんだぜ。

ちなみに、近年はキングズギャンビットはあまり指されないそうだ。ギャンビット(ポーンを捨てる手)なら現代はクイーンズギャンビットなのだそうな。

というわけで、日本国内の初期の強豪には英語屋が多いようだが、それも頷けるというものだ。

そう、話は盤上のポラリスだった。

主人公の少年(小学5年生)は自発的にチェスに興味を持ち、チェス教室に通う。あり得ねぇー、無理があるぅー。いや、別に非難しているわけじゃない。

欧米においてはごく当たり前にあることかもしれない。というか、極々自然に父親が教えるだろう。そして父親に勝ちたくて強くなる。

話は戻ってポラリス。1巻目にして主人公の少年は、グランドマスター(世界クラスの強豪)になると宣言する。..が、そりゃ、無理だよ。日本にはよい指導者もいなければ、子供向けのよい本もない。それにライバルもいないはずだ。

まぁ、そう言っちゃおしまいだし、夢がない。

コミック「盤上のポラリス」には夢がある。ぼくは今後出る巻まで含め全巻読むつもりだよ。(現在は3巻まで発行済み)

このコミックを見た若い人が、よーし、おれもグランドマスターになるぞーとなれば、外野としても楽しいね。ぼくも若ければね..。じゃ、若いころに逆戻りできたら、チェスのグランドマスターに挑戦するかい? あっ、ごめん、そのころにはもっと楽しいことやってたよ(笑)。

というわけで、楽しいことも終わったぼくは、いまからマスター(FM)に挑戦しようか。

あり得ねぇー。

 

オセロ始めました

オセロ

チェスに続いてオセロを始めた。

この歳まで、オセロを真面目にやろうと思ったことは一度もなかった。オセロなんて底が浅い、大人が真剣にやるようなもんじゃないと思っていた。オセロ九段がいると聞いて吹き出してしまったぼくだ。オセロが趣味の人から見たら敵以外の何者でもないようなぼくなのだ。

それがふとオセロをやってみようと思った。

   http://wars.fm/reversi?lang=ja

f:id:fxrobot:20151102230754j:plain

↑こいつのせいだ。

で、ぼくはこれに参戦したい。ぼくはまずは入門書を読み始めた。現在、まだ 1/3 ほどしか読み進んでいない。よくそれでこんな記事を書く気になったもんだね。うー、それだけじゃないのだ。

f:id:fxrobot:20151102230629j:plain

オセロのソフトを購入して対局を始めたのだ。そのソフトは、OthelloⅢといいアマゾンで税込1,291円で買えるんだ。上の画像は、OthelloⅢのレベル10に勝ったときのものだ。ちぇ、自慢かよ。悪いね。でもね、言いたくはないけど、レベル10にはたぶん誰だって勝てると思うよ。

f:id:fxrobot:20151102230640j:plain

現在、レベル10とまで対戦したのだ。入門書を読む前の挑戦だった。ようするに、OthelloⅢは完全な素人にも勝たせてくれる思い遣りのあるソフトなのだ。決してぼくが強いなどという自慢ではないぞ。レベル11以降は、入門書を読んでからやろうと思っている。計画的なぼくなのだ。

OthelloⅢによってぼくはオセロソフトに興味を持った。で、世界でもトップクラスと言われる2つのソフトを戦わせてみたのだ。Thell3 vs WZebra の一戦だ。

f:id:fxrobot:20151102230230j:plain

Thell3    :  http://sealsoft.jp/thell/            (セル)
WZebra :  http://radagast.se/othello/     (ゼブラ)

結果は、石が同数で引き分けとなった。

ゼブラは外国製のソフトだが、メニューには日本語が表示できる。これは、オセロが日本で発明されたものであり、歴代の世界チャンピオンも日本人が圧倒的で、ソフトの開発者も日本を尊重すると言うことなのだろうとぼくは思った。

セルとゼブラ、どちらのソフトも素晴らしい。これからぼくのオセロ研究の心強いパートナーとなってくれることだろう。オセロに関心のある人なら、ぜひダウンロードして使ってみるとよいと思う。

【 勝てたよ 】
f:id:fxrobot:20151102235707j:plain

ゼブラは便利な機能も多く、ぼくのお気に入りとなった。ゼブラは対局用と言うよりは研究用と考えているが、とりあえず、ゼブラの一番弱いの(一手読み)には勝つことができた。(黒 38 対 白 26)

【 世界最強?】
f:id:fxrobot:20151102230907j:plain

もう一つ世界最強と言われるオセロソフトがあるそうな。上の画像のソフトがそれだ。NTest という。もちろんダウンロードしようとしたが、作者のサイトが無効となってしまっている。残念。

その後、世界のサイトを彷徨って、NTest を見つけたのだ。ただ、まだ動かしていない。ファイルの素性に信頼が置けないからだ。だから、ここでも紹介はしない。

NTest は、IBMの研究員によって開発されたソフトらしい。もし、動かして安全性に問題がなく評判通りの強さであったなら、改めてこのブログで紹介するかもしれない。

とにかく、ぼく自身、早くちょっとは強くなりたいな。