nptclのブログ

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

整数を英語で表現する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さんたちが結構頑張っているようなので、 制限なしでいくらでも大きな数を対象すると決めました。

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