nptclのブログ

Common Lisp処理系nptの開発メモです。https://github.com/nptcl/npt

整数を英語で表現する4(序数と負数)

最後に、序数と負数について説明します。

序数

数が0~19までの序数はすでに表に出しています。
例えば13は下記の通り。

* (format t "~:R" 13)
thirteenth

20以上の場合、例えば43は次のようになる。

* (format t "~:R" 43)
forty-third

40であるfortyは通常の表記ですが、最後の単語である3が序数となります。 単語がいくつあっても、最後だけが序数表記となります。 数が50であった場合は、十の位が最後の単語になるため、 fiftyの序数が表記されます。

* (format t "~:R" 50)
fiftieth

複数の単語の例を挙げます。

* (format t "~:R" 1234)
one thousand two hundred thirty-fourth

hundredの場合は単純にthをつけます。

* (format t "~:R" 100)
one hundredth

それ以外のもの、も例えばthousandmillion、 あるいは巨大な単位milliquattuortrigintaducentillionなども、 単純に最後のthをつけるだけです。

例を挙げます。

thousand → thousandth
million → millionth
milliquattuortrigintaducentillion → milliquattuortrigintaducentillionth

実行例をあげます。

* (format t "~:R" 1000)
one thousandth

* (format t "~:R" 10000000000)
ten billionth

負数

負数については、単純に最初にminusnegativeをつけます。

例を示します。

[sbcl]

* (format t "~R" -100)
negative one hundred

* (format t "~:R" -100)
negative one hundredth

[ccl]

? (format t "~R" -100)
negative one hundred

? (format t "~:R" -100)
negative one hundredth

[clisp]

> (format t "~R" -100)
minus one hundred

> (format t "~:R" -100)
minus one hundredth

なお、cltl2では序数で負数の場合は、 最後にpreviousを印字するものもあるとのこと。 例えば次の通り。

* (format t "~:R" -4)
fourth previous

以上で整数を英語で表現する説明は終わりです。

整数を英語で表現する3(巨大な数)

前回はthousand, million, billionの次は何かという話題で終わらせました。 この3桁区切りの単位さえわかれば、無限に数を表現できることになります。 どうも、この単位を求める方法は決まっておらず、色々あるようです。 本投稿では、 The Conway-Wechsler System という方法について説明していきます。


【注意】今回の内容はThe Conway-Wechsler Systemそのものなので、 英語がわかる人は下記ページを見た方が正確です。

The Conway-Wechsler System
http://www.mrob.com/pub/math/largenum.html#conway-wechsler

Wikipediaではまた違った方法で説明しているようです。 本投稿では説明するつもりはないですが興味がある方はどうぞ。

Names of large numbers
https://en.wikipedia.org/wiki/Names_of_large_numbers


それでは単位を求めて行きます。 まずは対象となる数が、何番目の単位に該当するのかを求めます。 数が10の何乗かを求めます。 10なら1、10,000なら4になります。

求めた数から3を引きます。 1,000なら3-3=0、1,000,000,000なら9-3=6です。

引いた数を3で割り、商と余りを求めます。 もし余りが0ならoneから、1ならtenから、2ならone hundredから始まることになります。 求めた商が重要であり、解説ではNと表現されていました。

もし商Nが10未満の場合は、下記の表によって決定されます。

商N 英語
0 thousand
1 million
2 billion
3 trillion
4 quadrillion
5 quintillion
6 sextillion
7 septillion
8 octillion
9 nonillion

商Nが10以上の場合は、 商Nの一の位、十の位、百の位の数の組み合わせによって文字列を求めます。 ひとまずは商Nが10~999までの場合を考慮しましょう。 ちなみに商Nが999というのは、元の数が3000桁の場合となります。

組み合わせの表を示します。

商N 1の位 10の位 100の位
0 - - -
1 un (n) deci (nx) centi
2 duo (ms) viginti (n) ducenti
3 tre (*) (ns) triginta (ns) trecenti
4 quattuor (ns) quadraginta (ns) quadringenti
5 quin (ns) quinquaginta (ns) quingenti
6 se (sx) (n) sexaginta (n) sescenti
7 septe (mn) (n) septuaginta (n) septingenti
8 octo (mx) octoginta (mx) octingenti
9 nove (mn) nonaginta nongenti

表より商Nの一の位、十の位、百の位の文字をつなげて文字列を作ります。 ただし()が隣り合っている場合は、カッコ内の文字が等しいときにその文字を入れます。
例えば

septe(mn) + (ms)viginti = septemviginti 

この例では、(mn)(ms)でどちらにもmが含まれているため、 文字mを二つの単語の間に入れました。
他には

se(sx) + (mx)octoginta = sexoctoginta

カッコが連結しているのは一の位と十の位、あとは一の位と百の位であり、 十の位と百の位ではカッコが隣り合っていないので注意。

特別な場合として、一の位のtre(*)があります。 これは、隣り合っているカッコにsxが含まれている場合には、 文字sを入れます。
例えば

tre(*) + (mx)octingenti = tresoctingenti

この例では、(*)(mx)が隣り合っており、文字にxがあるため、 文字xではなく文字sを挿入しています。

求めた英単語の最後の母音を削除します。 母音はa,i,u,e,oであり、例えば次のようになります。

tresoctingenti → tresoctingent

英単語の最後に文字illionをつけます。 例えば下記の通り。

tresoctingent → tresoctingentillion

完成です。

例を挙げます。

英語
10の261乗 sexoctogintillion
10の2421乗 sexoctingentillion
10の309乗 duocentillion
10の603乗 ducentillion
10の312乗 trescentillion
10の903乗 trecentillion

以上で、商Nが0~999まで説明はしました。 では商Nが999が超えた場合を説明します。

まずは商Nを3桁区切りにします。 例えば求めた商Nが987654321であった場合は、

987,654,321

となります。考え方としては、

987 illi 654 illi 321 illion

のように、文字を少し変えて横に直列でつなぐことで求めます。 それぞれ3桁の単位を求めると次のようになります。

987    septemoctogintanongentillion
654    quattuorquinquagintasescentillion
321    unvigintitrecentillion

321以外の単語の最後についている「on」削除します。

987    septemoctogintanongentilli ★on削除
654    quattuorquinquagintasescentilli ★on削除
321    unvigintitrecentillion

単語をつなげます。

septemoctogintanongentilliquattuorquinquagintasescentilliunvigintitrecentllion

非常に長いが完成です。 あまりに長すぎるようにも思えますが、そもそも商Nが987654321という場合は 元々の数の桁数が2962962966であり、30億個近くも数値が連なる場合なので 単位もここまで長くなってしまうのです。

このアルゴリズムでは、単位が必ずillionで終わることが前提となっているのですが、 たった一つだけ、商Nが0の時はthousandなのでillionで終わりません。 そこでthousandではなく、nillionという表記で代用します。

例を挙げます。

1000        millinillion  (million + thousand)
1001        millimillion
1002        millibillion
1003        millitrillion
1013        millitredecillion
1234        milliquattuortrigintaducentillion
6560        sextillisexagintaquingentillion
19683       novendecillitresoctogintasescentillion
1000000     millinillinillion

以上で説明は終わりですが、注意点をいくつか。 このアルゴリズムは絶対ではなく、方言が色々あるようです。 基本的な考え方はラテン語をベースとしているようで、 ラテン語にとって自然な場合はこっちだろうということで、 人によって色んな考え方があるようです。

解説しているリンク先では詳しく説明されていますが、 例えば

The Conway-Wechsler Systemでは
    quinquadecillion, sedecillion, and novendecillion
だが、
    quindecillion, sexdecillion and novemdecillion
としてよく知られているとか、
    millinillion
ではなく
    millillion
と表現する場合があるとか、
    quinqua
より
    quin
の方が自然だろう

とかが話題として出ているので、 もし他のシステムと相違があって困った場合は確認してみてください。 例えば2の200乗の例では、sbclclispでは

one novemdecillion

で始まりますが、The Conway-Wechsler Systemでは

one novendecillion

となります。

その他にもWikipediaに載っている方法も何となく違って見えます。

Names of large numbers
https://en.wikipedia.org/wiki/Names_of_large_numbers


ここまででThe Conway-Wechsler Systemの解説は終わりですので、 最後にいくつか話題を残します。 まずは、本解説を用いて出力した2の200乗の結果を下記に示します。

one novendecillion, six hundred and six octodecillion, nine hundred and thirty-eight septendecillion, forty-four sedecillion, two hundred and fifty-eight quindecillion, nine hundred and ninety quattuordecillion, two hundred and seventy-five tredecillion, five hundred and forty-one duodecillion, nine hundred and sixty-two undecillion, ninety-two decillion, three hundred and forty-one nonillion, one hundred and sixty-two octillion, six hundred and two septillion, five hundred and twenty-two sextillion, two hundred and two quintillion, nine hundred and ninety-three quadrillion, seven hundred and eighty-two trillion, seven hundred and ninety-two billion, eight hundred and thirty-five million, three hundred and one thousand, three hundred and seventy-six

せっかくなのでgoogolについての話題もしておきます。 googolとは「10の100乗」を意味しており、 wikipediaによると検索サイトgooglegoogolの誤字がもとになっているとのこと。

The Conway-Wechsler Systemによると、10の100乗は下記のようになります。

ten duotrigintillion

あと、商Nが0から1000くらいまでならnptのテストケースに例がありますので示します。

https://github.com/nptcl/npt/blob/v0.1.1/test/case_large.txt

次の投稿では序数と負数について説明します。

整数を英語で表現する2(中学レベル)

あまり大きくない整数を英語で表す方法について説明します。 どれくらいかというと、0から億くらいでしょうか。 それ以上の整数の表現は次章になります。

自分は中学レベルの英語の知識も危うかったため調べました。 せっかくなのでその内容をここに記載しておきます。 俺もわからんぜって方は、ここじゃなく別のサイトに飛んで、 ちゃんとした所で勉強したほうがいいかもしれません。 間違っている可能性がありますので。

では、あまり大きくない整数をshort scaleの英語で 表現する方法について説明します。

まずは0から19までの表現を示します。 せっかくなのでCommon Lispを使って出力します。 これらは暗記するしかありません。

* (dotimes (i 20) (format t "~D: ~:*~R, ~:*~:R~%" i))
0: zero, zeroth
1: one, first
2: two, second
3: three, third
4: four, fourth
5: five, fifth
6: six, sixth
7: seven, seventh
8: eight, eighth
9: nine, ninth
10: ten, tenth
11: eleven, eleventh
12: twelve, twelfth
13: thirteen, thirteenth
14: fourteen, fourteenth
15: fifteen, fifteenth
16: sixteen, sixteenth
17: seventeen, seventeenth
18: eighteen, eighteenth
19: nineteen, nineteenth

出力は「数: 英語表記, 序数表記」となります。

20から99までの表現は、十桁と一桁を組み合わせて表現します。 20, 30, ...といった十桁の表現の仕方も、暗記するしかありません。

* (dotimes (i 10) (format t "~D: ~:*~R, ~:*~:R~%" (* i 10)))
0: zero, zeroth
10: ten, tenth
20: twenty, twentieth
30: thirty, thirtieth
40: forty, fortieth
50: fifty, fiftieth
60: sixty, sixtieth
70: seventy, seventieth
80: eighty, eightieth
90: ninety, ninetieth

それでは2桁の数を考えます。
例えば48の場合、40-8のようにあらわします。

【例】48 → forty-eight

十桁と一桁の間にハイフン - をつけます。

【例】67 → sixty-seven

十桁が0の場合は十桁を記載しません。

【例】7 → seven

一桁が0の場合も一桁は記載しません。

【例】60 → sixty

つまり、40はfortyでありforty-zeroとは書かないし、 7はsevenでありをzeroty-sevenと書きません。

百の位が出てきた場合は、「百桁 hundred 下二桁」となります。 例えば123の場合は、1と23を分けて表記するため、

one hundred twenty-three

のようになります。

345の場合は

three hundred forty-five

205の場合は、十桁が省略されるので

two hundred five

560の場合は、一桁が省略されるので

five hundred sixty

800の場合は、十桁と一桁が省略されるので

eight hundred

これで0から999まで表現できました。

それ以上の数は、三桁に分けて特別な単位を付与します。 例えば1234567890の場合は、三桁区切りにすると次のようになります。

1,234,567,890

左のカンマから順に十億、百万、千に対応します。 英語ではそれぞれ次のように表現されます。

数値 英語 日本語
1,000,000,000 billion 十億
1,000,000 million 百万
1,000 thousand

考え方としては、次のようになります。

1 billion, 234 million, 567 thousand, 890

つまり、

* (format t "~R" 1234567890)
one billion two hundred thirty-four million five hundred sixty-seven thousand eight hundred ninety

注意点としては、三桁の場合と同じようにzeroは省略し、 記載が必要ない場合は単位も省略します。

例えば

1,000,000,000

one billion

であり、

one billion zero million zero thousand zero

ではありません。

それではCommon Lisp処理系の出力例を見てみます。

[sbclの実行例]

* (format t "~R" 1234567890)
one billion two hundred thirty-four million five hundred sixty-seven thousand eight hundred ninety

[clispの実行例]

* (format t "~R" 1234567890)
one billion, two hundred and thirty-four million, five hundred and sixty-seven thousand, eight hundred and ninety

上記2例では少しだけ表現が違っています。 sbclに対して、clispでは三桁区切りでカンマが挿入されています。 また、hundredの次にandが挿入されています。 この辺りはいろいろな流儀があるのでしょう。 好みでいいと思います。

今回は三桁区切りの表現方法を説明しました。 それではthousand, million, billionの次は何でしょうか。 これが次章の本題となります。

整数を英語で表現する1

これから整数を英語で表す方法をひたすら説明します。

Common Lispのformat関数~Rでは、整数を英語で表現できます。
例えば下記の通り。

* (format t "~R" 13)
thirteen

* (format t "~R" 1234)
one thousand two hundred thirty-four

* (format t "~R" -200)
minus two hundred

オプションのコロンをつけて、~:Rとすることで序数を表すことができます。 序数とは、one, two, threeじゃなくて、first, second, thirdみたいなやつです。

* (format t "~:R" 13)
thirteenth

* (format t "~:R" 2)
second

* (format t "~:R" -987)
minus nine hundred eighty-seventh

この整数を英語で表現するという機能を開発したときの話です。 引数の整数とは一体どれくらい大きな値を考慮するべきでしょうか。
一億、一兆まで? 一無量大数まで? それ以上?
ANSI Common Lispの規格書には記載が見つけられませんでしたが、 cltl2には詳しく書かれていました。

話題にしたい部分を抜き出すと、

  • 2の200乗の表示例がある。
  • 999,999,999を超える場合は10進数表記でもいいんじゃない?

2の200乗というのは10進数で61桁という巨大な数値であり、下記のようになります。

* (ash 1 200)
1606938044258990275541962092341162602522202993782792835301376

日本語で記載すると

1那由他6069阿僧祇3804恒河沙・・・億3530万1376

みたいな感じなります。
那由他ってなんだ。

cltl2の表示例を下記に示します。
https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node200.html#SECTION002633000000000000000

one times ten to the sixtieth power six hundred six times ten to the
fifty-seventh power nine hundred thirty-eight septdecillion forty-four
sexdecillion two hundred fifty-eight quindecillion nine hundred ninety
quattuordecillion two hundred seventy-five tredecillion five hundred 
forty-one duodecillion nine hundred sixty-two undecillion ninety-two 
decillion three hundred forty-one nonillion one hundred sixty-two
octillion six hundred two septillion five hundred twenty-two sextillion
two hundred two quintillion nine hundred ninety-three quadrillion seven 
hundred eighty-two trillion seven hundred ninety-two billion eight 
hundred thirty-five million three hundred one thousand three hundred
seventy-six

Another implementation prints it this way (note the use of plus):

one times ten to the sixtieth power plus six hundred six times ten to 
the fifty-seventh power plus ... plus two hundred seventy-five times 
ten to the forty-second power plus five hundred forty-one duodecillion 
nine hundred sixty-two undecillion ...  three hundred seventy-six
(I have elided some of the text here to save space.)

では999,999,999を超える場合は10進数表記でもよいというのは何故でしょうか。 ここで話題に出しておかなければいけないのは、 数値を英語で表記する際の「scale」の問題です。 scaleというのは、方言みたいなもので、long scaleとshort scaleが存在します。 昔からアメリカはshort scaleであり、 long scaleを使っていたイギリスも、つい最近?はshort scaleに 移行したとかしなかったとか。 たぶんみなさまが知ってるのはshort scaleだと思います。

詳細はここ
https://ja.wikipedia.org/wiki/西洋の命数法

999,999,999を超えるとshort scaleとlong scaleで 英語の表現が変わってきてしまいます。 例えばbillionという単位は、short scaleでは十億ですが、 long scaleでは一兆のことになります。 だから10進数表記を勧めるとの記載があるのです。

でも多くのCommon Lisp処理系ではとんでもない数字でも 何とか頑張って出してしまいます。 2の200乗を各処理系で出力してみます。

clispの場合

> (format t "~R" (ash 1 200))
one novemdecillion, six hundred and six octodecillion, nine hundred and thirty-eight septendecillion, forty-four sexdecillion, two hundred and fifty-eight quindecillion, nine hundred and ninety quattuordecillion, two hundred and seventy-five tredecillion, five hundred and forty-one duodecillion, nine hundred and sixty-two undecillion, ninety-two decillion, three hundred and forty-one nonillion, one hundred and sixty-two octillion, six hundred and two septillion, five hundred and twenty-two sextillion, two hundred and two quintillion, nine hundred and ninety-three quadrillion, seven hundred and eighty-two trillion, seven hundred and ninety-two billion, eight hundred and thirty-five million, three hundred and one thousand, three hundred and seventy-six

sbclの場合

* (format t "~R" (ash 1 200))
one novemdecillion six hundred six octodecillion nine hundred thirty-eight septendecillion forty-four sexdecillion two hundred fifty-eight quindecillion nine hundred ninety quattuordecillion two hundred seventy-five tredecillion five hundred forty-one duodecillion nine hundred sixty-two undecillion ninety-two decillion three hundred forty-one nonillion one hundred sixty-two octillion six hundred two septillion five hundred twenty-two sextillion two hundred two quintillion nine hundred ninety-three quadrillion seven hundred eighty-two trillion seven hundred ninety-two billion eight hundred thirty-five million three hundred one thousand three hundred seventy-six

cclの場合

? (format t "~R" (ash 1 200))
 エラー

そんなに頑張らなかったcclが一番賢いような気がします。

上記2例は全てshort scaleで出力されています。 調査した範囲のCommon Lisp処理系では全部short scaleでした。 たぶん日本でなじみが深いのもshort scaleだと思うので、 本投稿の説明はすべてshort scaleで説明することにしました。

最初の疑問の回答ですが、どれくらいの数を対象にするべきかというと、 999,999,999制限で絶対に問題ないでしょう。 でも他のLispさんたちが結構頑張っているようなので、 制限なしでいくらでも大きな数を対象すると決めました。

では次の投稿から数値を英語で表現する方法について説明します。 自分は中学レベルの英語の知識も危ういので、 最初は小さな数から説明し、次に巨大な数を説明します。

遅すぎるPCでsbclのソースをコンパイルする

遅すぎるPC上でsbclのソースをコンパイルすると、途中でエラーが発生して止まります。 あまり問題になっていないように見えるのですが、 みんないいコンピュータを使用しているからなのでしょう。

うちにあるのはクソみてえなPCばかりで、 FreeBSDportsコンパイルしてもあっさりエラーになってしまいます。 エラーの内容は下記の通り。

# make
・・・
・・・
WARNING! Some of the contrib modules did not build successfully or pass
their self-tests. Failed contribs:"
  sb-concurrency
      410.14 real      1025.96 user       112.83 sys
*** Error code 1

Stop.
make[1]: stopped in /usr/ports/lang/sbcl
*** Error code 1

Stop.
make: stopped in /usr/ports/lang/sbcl
#

もっとさかのぼってみると、次のようなエラーが生じていました。

Doing 25 pending tests of 25 tests total.
 SB-CONCURRENCY-TEST::FRLOCK.1 SB-CONCURRENCY-TEST::QUEUE.1
 SB-CONCURRENCY-TEST::QUEUE.2 SB-CONCURRENCY-TEST::QUEUE.3
 SB-CONCURRENCY-TEST::QUEUE.4 SB-CONCURRENCY-TEST::QUEUE.5
 SB-CONCURRENCY-TEST::QUEUE.T.1 SB-CONCURRENCY-TEST::QUEUE.T.2
 SB-CONCURRENCY-TEST::QUEUE.T.3 SB-CONCURRENCY-TEST::MAILBOX-TRIVIA.1
 SB-CONCURRENCY-TEST::MAILBOX-TRIVIA.2 SB-CONCURRENCY-TEST::MAILBOX-TRIVIA.3
 SB-CONCURRENCY-TEST::MAILBOX-TIMEOUTS
 SB-CONCURRENCY-TEST::MAILBOX.SINGLE-PRODUCER-SINGLE-CONSUMER
 SB-CONCURRENCY-TEST::MAILBOX.SINGLE-PRODUCER-MULTIPLE-CONSUMERS
 SB-CONCURRENCY-TEST::MAILBOX.MULTIPLE-PRODUCERS-SINGLE-CONSUMER
Test SB-CONCURRENCY-TEST::MAILBOX.MULTIPLE-PRODUCERS-MULTIPLE-CONSUMERS failed
Form: (SB-CONCURRENCY-TEST::TEST-MAILBOX-PRODUCERS-CONSUMERS :N-SENDERS 50
                                                             :N-RECEIVERS 50
                                                             :N-MESSAGES 1000)
Expected values: (:RECEIVED . 50000)
                 (:GARBAGE . 0)
                 (:ERRORS . 0)
                 (:TIMEOUTS . 0)
Actual values: (:RECEIVED . 48389)
               (:GARBAGE . 0)
               (:ERRORS . 0)
               (:TIMEOUTS . 6).
 SB-CONCURRENCY-TEST::MAILBOX.INTERRUPTS-SAFETY.1 SB-CONCURRENCY-TEST::GATE.0
 SB-CONCURRENCY-TEST::GATE.1 SB-CONCURRENCY-TEST::GATE.2
 SB-CONCURRENCY-TEST::GATE-DEADLINE.1 SB-CONCURRENCY-TEST::GATE-DEADLINE.2
 SB-CONCURRENCY-TEST::GATE-TIMEOUT.1 SB-CONCURRENCY-TEST::GATE-TIMEOUT.2
1 out of 25 total tests failed:
   SB-CONCURRENCY-TEST::MAILBOX.MULTIPLE-PRODUCERS-MULTIPLE-CONSUMERS.
WARNING: ignoring expected failures in test-op
Unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                    {10005305B3}>:
  test-op failed with unexpected failures

大体はこいつ、mailboxのせいです。 PCが遅すぎるからsb-concurrencyのテストでタイムアウトするのです。 仕方がないので次のようにファイルを変更してからコンパイルを行います。

--- contrib/sb-concurrency/tests/test-mailbox.lisp.error    2017-03-01 04:51:29.000000000 +0900
+++ contrib/sb-concurrency/tests/test-mailbox.lisp  2017-03-26 11:14:54.834397000 +0900
@@ -204,10 +204,10 @@

 #-win32
 (deftest mailbox.multiple-producers-multiple-consumers
-    (test-mailbox-producers-consumers :n-senders 50
-                                      :n-receivers 50
-                                      :n-messages 1000)
-  (:received . 50000)
+    (test-mailbox-producers-consumers :n-senders 5
+                                      :n-receivers 5
+                                      :n-messages 1)
+  (:received . 5)
   (:garbage  . 0)
   (:errors   . 0)
   (:timeouts . 0))

sbclのバージョンによって行が違うでしょうから、 上のdiffは参考にする程度で手で書き換えてください。

場合によっては他にもエラーが生じるので、 そのたびにテストケースを変更しなければなりません。 頻度は少ないですが、それなりに生じるものはfrlockです。

--- contrib/sb-concurrency/tests/test-frlock.lisp.error 2017-05-17 10:57:20.356675776 +0900
+++ contrib/sb-concurrency/tests/test-frlock.lisp   2017-05-17 10:57:30.386806999 +0900
@@ -87,7 +87,7 @@
 #+sb-thread
 (deftest* (frlock.1)
     (handler-case
-        (sb-ext:with-timeout 10
+        (sb-ext:with-timeout 100
           (test-frlocks #+win32 :outer-write-pause #+win32 t ))
       (sb-ext:timeout (c)
         (error "~A" c)))

エラーはconcurrencyで出力されているため、 遅すぎるPCにスレッドはいらんだろうという考えで コンパイル時にthreadを無効にしてもいいかもしれません。


話はかなりずれますが、sbclを手動でコンパイルするとき、 threadを使いたい場合は、例えばこんな感じでmakeを行います。

$ sh make.sh --fancy

ファンシー?

なにやら可愛らしいですねって思ってたんですが、 fancyというのはそういう意味はないって 英語部さんのサイトで説明されていました。

勉強になります。

【参考】ファンシー
https://www.nijntje.nl/
https://www.miffy.com/
https://www.dickbruna.jp/

clispをFreeBSDにインストールする

【追記】13.0-RELEASEの手順はこちら FreeBSD 13.0-RELEASEでclispをソースから構築 - nptclのブログ
【追記】portsclispが追加されました clispをFreeBSDにインストールする2 - nptclのブログ
【追記】最新バージョンのclispを入れる手順を追記しました

大昔のFreeBSDでは、clispが普通にportsで利用できていたように思えます。 しかし、ある日忽然と消えてしまいました。 clisp本家からたどれる、 Get CLISP->FreeBSD にはDEPRECATEDとか書かれています。 だからもう利用できません。

本当にそうなのか? 少なくとも自分はclispがないと生きていけないんですが、 みんな諦めて別のを使っているのでしょうか? たぶん諦めた方が賢明かもしれませんが、 ここではFreeBSDclispをインストールする方法を説明します。

FreeBSDから削除された理由は、たぶんFreeBSDの標準コンパイラgccからclangに変わったからだと思います。 clangではclispコンパイルできませんでした。 結構がんばったのですが、gccじゃないとコンパイルは無理っぽい。

gccportsから導入できるはずですが、 clispのためだけに入れるのも嫌だったので、 ここでは、ローカル環境でclispコンパイルする方法を示します。 ちなみに確認用に実施した環境は FreeBSD 11.1-RELEASE (amd64)。

事前準備

shellは/bin/shで説明します。 csh系を使っている場合は切り替えてください。

% /bin/sh
$

方法はgccをローカルに入れて、そのあとにclispコンパイルするという流れとなります。 手順では、$HOME/work配下に下記のディレクトリを作成します。

ディレクト 説明
install 作業用
gcc gccコンパイラ一式
clisp clisp一式

ディレクトリ名をいちいち入力するのが面倒なので、 作業用ディレクトリ用の環境変数を設定します。

$ work="${HOME}/work"
$ gcc="${HOME}/work/gcc"
$ clisp="${HOME}/work/clisp"

作業用ディレクトリを作成します。

$ mkdir ${work}
$ mkdir ${work}/install

gccのインストール

最新の安定版gccは8.3.0でした。 最低限の依存関係を考慮した場合、下記のファイルが必要になります。

  • gmp-6.1.2.tar.xz
  • mpc-1.1.0.tar.gz
  • mpfr-4.0.2.tar.xz
  • isl-0.20.tar.xz
  • make-4.2.1.tar.bz2
  • gcc-8.3.0.tar.xz

ダウンロード

$ cd ${work}/install
$ fetch http://ftp.jaist.ac.jp/pub/GNU/gmp/gmp-6.1.2.tar.xz
$ fetch http://ftp.jaist.ac.jp/pub/GNU/mpc/mpc-1.1.0.tar.gz
$ fetch http://ftp.jaist.ac.jp/pub/GNU/mpfr/mpfr-4.0.2.tar.xz
$ fetch http://isl.gforge.inria.fr/isl-0.20.tar.xz
$ fetch http://ftp.jaist.ac.jp/pub/GNU/make/make-4.2.1.tar.bz2
$ fetch http://ftp.jaist.ac.jp/pub/GNU/gcc/gcc-8.3.0/gcc-8.3.0.tar.xz

ミラーサイトjaistさんを利用させていただきました。 ありがとうございます。

gmpの導入

$ cd ${work}/install
$ tar Jxf gmp-6.1.2.tar.xz
$ cd gmp-6.1.2
$ ./configure --prefix=${gcc}
$ make
$ make install
$ make clean

mpfrの導入

$ cd ${work}/install
$ tar Jxf mpfr-4.0.2.tar.xz
$ cd mpfr-4.0.2
$ ./configure --prefix=${gcc} --with-gmp=${gcc}
$ make
$ make install
$ make clean

mpcの導入

$ cd ${work}/install
$ tar zxf mpc-1.1.0.tar.gz
$ cd mpc-1.1.0
$ ./configure --prefix=${gcc} --with-gmp=${gcc} --with-mpfr=${gcc}
$ make
$ make install
$ make clean

islの導入

$ cd ${work}/install
$ tar Jxf isl-0.20.tar.xz
$ cd isl-0.20
$ ./configure --prefix=${gcc} --with-gmp-prefix=${gcc}
$ make
$ make install
$ make clean

GNU makeの導入

$ cd ${work}/install
$ tar jxf make-4.2.1.tar.bz2
$ cd make-4.2.1
$ ./configure --prefix=${gcc}
$ make
$ make install
$ make clean

gccの導入

$ cd ${work}/install
$ tar Jxf gcc-8.3.0.tar.xz
$ mkdir gcc-object
$ cd gcc-object
$ export LD_LIBRARY_PATH=${gcc}/lib:$LD_LIBRARY_PATH
$ export LIBRARY_PATH=${gcc}/lib
$ export C_INCLUDE_PATH=${gcc}/include
$ export CPLUS_INCLUDE_PATH=${gcc}/include
$ export LC_COLLATE=C
$ ../gcc-8.3.0/configure \
--enable-languages=c \
--prefix=${gcc} \
--with-gmp=${gcc} \
--with-mpfr=${gcc} \
--with-mpc=${gcc} \
--with-isl=${gcc} \
--disable-bootstrap
$ ${gcc}/bin/make
$ ${gcc}/bin/make install
$ ${gcc}/bin/make clean

確認

これで下記のファイルからgccを使用できます。

  • ${HOME}/work/gcc/bin/gcc

確認してみます。

$ ${HOME}/work/gcc/bin/gcc --version
gcc (GCC) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

注意点があり、環境変数をちゃんと設定しないと コンパイルが上手く動作しません。 この辺りはclispコンパイル時にちゃんと見ていきます。

clispのインストール

前の手順にてすでに設定されていますが、 念のため次の環境変数が設定されているか確認してください。

$ work="${HOME}/work"
$ gcc="${HOME}/work/gcc"
$ clisp="${HOME}/work/clisp"

前手順ではローカル環境にgccを導入したので、環境変数の設定をします。

$ export CC=${gcc}/bin/gcc
$ export LD_LIBRARY_PATH=${gcc}/lib:$LD_LIBRARY_PATH
$ export LIBRARY_PATH=${gcc}/lib
$ export C_INCLUDE_PATH=${gcc}/include
$ export CPLUS_INCLUDE_PATH=${gcc}/include

最新版clispは2.49でした。 最低限の依存関係を考慮した場合、下記のファイルが必要になります。

  • libsigsegv-2.12.tar.gz
  • ffcall-1.10.tar.gz
  • readline-8.0.tar.gz
  • clisp-2.49.tar.bz2

ダウンロード

$ cd ${work}/install
$ fetch http://ftp.jaist.ac.jp/pub/GNU/libsigsegv/libsigsegv-2.12.tar.gz
$ fetch http://www.haible.de/bruno/gnu/ffcall-1.10.tar.gz
★もしsslエラーになったら下記を実行
    $ fetch --no-verify-peer http://www.haible.de/bruno/gnu/ffcall-1.10.tar.gz
$ fetch http://ftp.jaist.ac.jp/pub/GNU/readline/readline-8.0.tar.gz

【追記】リリース版のclispを入れる場合

$ fetch http://ftp.jaist.ac.jp/pub/GNU/clisp/release/2.49/clisp-2.49.tar.bz2

【追記】最新版のclispを入れる場合

$ fetch --no-verify-peer https://gitlab.com/gnu-clisp/clisp/-/archive/master/clisp-master.tar.bz2

libsigsegvの導入

$ cd ${work}/install
$ tar zxf libsigsegv-2.12.tar.gz
$ cd libsigsegv-2.12
$ ./configure --prefix=${clisp}
$ make
$ make install
$ make clean

ffcallの導入

$ cd ${work}/install
$ tar zxf ffcall-1.10.tar.gz
$ cd ffcall-1.10
$ ./configure --prefix=${clisp}
$ make
$ make install
$ make clean

readlineの導入

$ cd ${work}/install
$ tar zxf readline-8.0.tar.gz
$ cd readline-8.0
$ ./configure --prefix=${clisp}
$ make
$ make install
$ make clean

clispの導入

$ cd ${work}/install

★リリース版の場合
$ tar jxf clisp-2.49.tar.bz2
$ cd clisp-2.49

★最新版の場合
$ tar jxf clisp-master.tar.bz2
$ cd clisp-master

$ ./configure --prefix=${clisp} \
--with-libsigsegv-prefix=${clisp} \
--with-libffcall-prefix=${clisp} \
--with-readline-prefix=${clisp} \
--disable-mmap
$ cd src
$ make
$ make install
$ make clean

確認

これで下記のファイルが作成されます。

  • ${HOME}/work/clisp/bin/clisp

実行できるか確認します。

$ ${HOME}/work/clisp/bin/clisp
  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo
  I I I I I I I      8     8   8           8     8     o  8    8
  I  \ `+' /  I      8         8           8     8        8    8
   \  `-+-'  /       8         8           8      ooooo   8oooo
    `-__|__-'        8         8           8           8  8
        |            8     o   8           8     o     8  8
  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8

Welcome to GNU CLISP 2.49 (2010-07-07) <http://clisp.cons.org/>

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010

Type :h and hit Enter for context help.

[1]> (quit)
Bye.
$

環境変数が設定されていなくても実行できるはずなので、 確認をするなら一度ログアウトしてから実施してみてください。

Common Lispを作りたい

Common LispC言語で作りたいと思い、コツコツとやって来て、 だいたい半分くらいまで作り上げました。 しかし最近になって作成する時間があまりとれなくなったため、 せっかくなので現状で公開することにしました。

https://github.com/nptcl/npt

とっても不完全でかなり遅いですが、なんとなく形にはなっています。 開発は中断したわけではないので、細く続けていこうと思っています。 FreeBSD, Linuxで実行できます。