数学」カテゴリーアーカイブ

「オイラーの定数ガンマ γで旅する数学の世界」を読んだ

ずっと積んであった「オイラーの定数ガンマ γで旅する数学の世界」を読みました。

この本は私が学部生の頃(2010年代前半)に生協書籍部で見つけて、面白そうだったので買った本です。しかし、この本にはある欠点(後述)があり、学部の時は読むのを断念しました。

この本はどういう本か

数学を代表する定数といえば、円周率π、自然対数の底e、虚数単位iが挙がるでしょう。少し物知りな人は、第4の定数(実数としては、第3の定数)としてオイラーの定数γ(ガンマ)を挙げるかもしれません。

この本は、タイトルの通り、オイラーの定数ガンマの話題を扱った本です。教科書というよりは、読み物です。数学に関するエピソードがふんだんに散りばめられています。

関連する話題として、調和級数、ゼータ関数なども扱っています。本の後半は素数定理とリーマン予想の話題です。

双子素数の逆数和の話で「Pentium FDIVバグが見つかるきっかけになったのが双子素数の逆数和の計算だった」というエピソードに触れられており、プログラマーとしては興味深かったです。

翻訳の質が低い

学部生の時にこの本を読むのを断念したのは、翻訳の質が低いと感じたからです。日本語がこなれていないというか。(これは邦訳だけを読んだ感想です。この記事は英語の原著を読まずに書かれています。)

私が翻訳の質について敏感であるという側面は多分あります。私は中学生の頃に2chの「ハリーポッターの邦訳のここがおかしい」みたいなスレッドに入り浸っていました(そのスレッドでは、Lily, Petunia姉妹の上下が邦訳ではグダグダになっているとか、vanishとbanishを取り違えている疑惑とか、The Boy Who LivedとThe boy who livedの訳し分けとかを語っていました)。大学以降では、IT技術の記事を扱っているpostd.ccというサイトの翻訳の質が低いようなことを短文投稿SNSで愚痴っていました。

多少翻訳の質が低くても、気にせずに読める人は多いのでしょう。しかし、私にとっては翻訳の質が低いのはノイズになるのでした。今回も「読んだ」というよりは「スキミングした」の方が近いかもしれません。

翻訳の質の定量化は難しいですが、引っかかった箇所を具体的にいくつか挙げます。私の手元にあるのは初版第2刷です。

xii(序文):

場合によって必要になるのは,彼の名前Eulerの発音の仕方でしょう.もちろん,“Oiler”ですが.

これ日本語の本ですよね。「Oiler」ってどう見ても英語圏向けの注釈ですよね。日本語版に要ります?要らないでしょ、「オイラー」ってすでに何回も書いているのに。全体的に、「日本語の本にしよう」という気概が足りないのではないかと思います。

5ページ:

ネイピアは確かにlogarithmという語(ratioとnumberを意味するラテン語を組み合わせた語)を作り,タイトルに含めましたが,…

「ratio」と「number」は英語の原著での表現なのだと思いますが、そこは日本語に訳さないのか!?と思ってしまいました。

18ページ、オイラーについて:

この定義は1770年刊の彼のベストセラーになった代数学の教科書,Complete Introduction to Algebraに出てきます.

オイラーが書いた本は多分英語ではないですよね。Elements of Algebra – Wikipediaによるとロシア語か?タイトルの英語への直訳がComplete Introduction to Algebraなのだと思いますが、日本語に訳すにあたってはタイトルも日本語に訳して、必要なら原語でのタイトルも併記する形にするべきだったと思います。

132ページ:

現代的なコンピュータで「芸術的(state-of-the-art)」なソフトウェアを使って計算すれば簡単にできます.

state-of-the-artは「芸術的」ではないですね……。最近AI周りでSOTAという語をよく見るようになりましたが、辞書を引くと「最先端」という意味が出てきます。直訳すると「技術(art)の現在の状態」→その時点での最高の技術を集めたもの、てな感じでしょうか。

こういう誤訳は、単発なら可愛いものですが、それ以外の部分で「全体的に質が低い」という印象を与えてしまうと、「質が低い」ことのエビデンスとして使われてしまうということです。

261ページ:

セルバーグは,1942年に,ハーディのオリジナルの結果をさらに進めて,すべての非自明な零点の正の部分は臨界線上にあることを示しました(これは微妙ですが,重要な区別です.例えば,ℤは無限ですが,ℝと比べた正確な大きさを測定すると0です).

「零点の正の部分」って意味伝わりますか?前後の文脈から判断して、「非自明な零点のうち臨界線上にあるものの存在割合(proportion)が正である」という風に私は解釈しましたが、合っているかは知りません(Selberg (1942)を読めばいいのでしょうが)。とにかく、もっと良い訳し方があったのではないかと思います。

このほかにも、一文が長すぎたり、直訳調だったりします。日本語ネイティブならもっと流暢な日本語にできないのか?と思ってしまいますが、訓練していないと難しいんでしょうね。


まあ翻訳にケチをつける人(私のような)がより良い翻訳をできるのか?というとそれは別問題だと思います。しかし、お金を出して買った本がイマイチだった時に愚痴る権利は2800円+税の分(実際は大学生協でさらに1割引)くらいはあると思います。

繰り返しますが、多くの人は翻訳の質を気にせずに読めると思います。ただ、私のように翻訳の質が気になる人(下手な訳がノイズになる人)は英語の原著を買った方が良いかもしれません。原著は多分これです:Amazon | Gamma: Exploring Euler’s Constant (Princeton Science Library) | Havil, Julian, Dyson, Freeman | Mathematical Physics

前にも共立出版の本をレビューしました(「数学ソフトウェアの作り方」を読んだ)が、共立出版のWebサイトを見ても誤植等の報告をどこにすればいいのかよくわからないんですよね(「お問い合わせ」でいいのか?)。そんなに自信があるならもうちょっと品質を頑張って欲しいものです。

「ものが等しい」ということ

最近、「ものの等しさ」について思うところが何点かあるので書き殴っておく。

数学での「等しさ」

ものを数学的な議論に載せる上で、「等しさ」というのは基本的な概念だと思われる。扱う対象の「等しさ」について合意ができない人と数学的な議論はできない。

続きを読む

TwoSumの証明に2週間かかった

前に「浮動小数点数小話」という同人誌を出しましたが、私としては浮動小数点数についてもっとちゃんとした本をいずれ出したいと思っています。執筆に着手するのは早い方が良いので、浮動小数点数についてのまとめノートみたいものを書き始めています。

続きを読む

代数構造の「マグマ」と、定義の動機づけ

マグマ

「マグマ」という代数構造がある。

マグマとは、集合とその上の二項演算の組である。

普通の代数構造だと、二項演算について結合法則や単位元の存在など、なんらかの法則を課すことが多いが、マグマは何の法則も課さない。

続きを読む

整数除算を浮動小数点演算でエミュレートできるか

古典的な(BigInt以前の)JavaScriptは数値型が倍精度浮動小数点数のみでした。5.2までのLuaも同様です。

このような言語で整数除算を行いたい場合は、浮動小数点演算を経由して行うことになります。例えばJavaScriptで32ビット整数の除算をやるならこんな感じです:

// x, yは整数値とする
function Int_div(x, y) {
    return Math.floor(x / y);
}
function Int_quot(x, y) {
    return Math.trunc(x / y);
}
// 0除算やオーバーフローはここでは無視する

さて、浮動小数点演算と言えば誤差です。この「浮動小数点演算による整数除算のエミュレート」は誤差の影響を受けないのでしょうか?

続きを読む

2^53+1 は素数か

ふと \(2^{53}+1\) が素数かどうか気になりました。

短い答え:No

Linuxだと factor コマンドで素因数分解できます。

$ factor $((2**53+1))
9007199254740993: 3 107 28059810762433

macOSだとHomebrewやMacPortsでcoreutilsを入れる必要があります。

筆者のMacには factor コマンドは入っていなかったので、最初はMaximaで確認しました:

$ maxima    
Maxima 5.45.1 https://maxima.sourceforge.io
using Lisp SBCL 2.2.9
Distributed under the GNU Public License. See the file COPYING.
Dedicated to the memory of William Schelter.
The function bug_report() provides bug reporting information.
(%i1) factor(2^53+1);
(%o1)                        3 107 28059810762433

というわけで、 \(2^{53}+1\) は\[2^{53}+1=3\times 107\times 28059810762433\]と素因数分解でき、素数ではありません。

暗算でもできるのでは?

今回調べたいのは \(2^{53}+1\) という形の数です。ちょっと頭を使えば、この数が3で割り切れることがわかります:\begin{align*}2^{53}+1&=2^{53}-(-1)^{53}\\&=(2-(-1))(2^{52}+\cdots+2^{52-i}\cdot(-1)^i+\cdots+(-1)^{52})\end{align*}と因数分解できます。

一般化すると、\(2^{2m+1}+1\)の形の整数はすべて3で割り切れることがわかります。つまり、\(m\neq 0\)で\(2^{2m+1}+1\)が3よりも大きくなる場合はこの形の数はすべて合成数です。

もっと一般化

もっと一般に、\(2^n+1\)の形の整数が素数となるのは\(n=0\)または\(n=2^k\ (k\geq 0)\)の場合に限られます。

\(n=2^k(2m+1)\)とおくと、\begin{align*}2^n+1&=2^{2^k(2m+1)}+1\\&=\left(2^{2^k}\right)^{2m+1}+1\\&=\left(2^{2^k}\right)^{2m+1}-(-1)^{2m+1}\\&=\left(2^{2^k}-(-1)\right)\left(\left(2^{2^k}\right)^{2m}+\cdots+\left(2^{2^k}\right)^{2m-i}\cdot(-1)^i+\cdots+(-1)^{2m}\right)\\
&=\left(2^{2^k}+1\right)\left(\left(2^{2^k}-1\right)\left(2^{2^k}\right)^{2m-1}+\cdots+\left(2^{2^k}-1\right)\left(2^{2^k}\right)^{2(m-i)+1}+\cdots+\left(2^{2^k}-1\right)\cdot 2^{2^k}+1\right)\\
&=\left(2^{2^k}+1\right)\left(\sum_{i=0}^{m-1} \left(2^{2^k}-1\right)\left(2^{2^k}\right)^{2i+1}+1\right)\end{align*}と因数分解できます。

\(k\geq 0\)なので、\(2^{2^k}+1\geq 3\)であり、最初の因数は非自明です。そして、2番目の因数に登場する\(2^{2^k}-1\)は1以上で、\(m\geq 1\)ならば2番目の因数も非自明です。

よって、\(2^{2^k(2m+1)}+1\)の形の数が素数となるのは\(m=0\)の場合に限ることがわかりました。

フェルマー数

\(2^{2^k}+1\)の形の数はフェルマー数と呼ばれています。\(k=0,1,2,3,4\)の場合はこれは素数となり、フェルマー素数と呼ばれています。

ところでなんで \(2^{53}+1\) を調べたかったのか

一部のプログラミング言語では、倍精度浮動小数点数型を唯一の数値型として提供しています。BigInt以前のJavaScriptや、5.2までのLuaなど。

こういう言語では、絶対値が\(2^{53}\)以下の整数は正確に表現できます。そして演算結果の絶対値がそれを超えると、丸めが発生して正しい答えが返ってきません。JavaScriptで試してみましょう:

$ node
Welcome to Node.js v17.9.1.
Type ".help" for more information.
> 2**53 - 1
9007199254740991
> 2**53
9007199254740992
> 2**53 + 1
9007199254740992
> 2**53 + 2
9007199254740994
> 2**53 + 3
9007199254740996

2**53 + 1 を表現できておらず、「表現可能な最も近い値のうち、仮数部の末尾が偶数な方」が表示されています(最近接偶数丸め)。

では、演算結果が「正確に表現できる範囲」を超えたかどうかはどうやったらわかるでしょうか?まず、演算結果の絶対値が\(2^{53}+2\)以上であれば間違いなく超えています。

では、演算結果の絶対値が\(2^{53}\)以下なら結果は正確と言えるでしょうか?否ですね。2**53 + 1 の演算結果は\(2^{53}\)以下であるにも関わらず、不正確です。

一方、演算結果の絶対値が\(2^{53}-1\)以下であれば結果は正確であることが保証されます。この範囲、\([-(2^{53}-1),2^{53}-1]\)はJavaScript界隈ではsafe integerと呼ばれています。

さて、筆者が作っているStandard ML処理系、LunarMLでもsafe integerに相当する整数型を提供できると便利です。提供するとするとビット数は符号ビットも含めて54ビット、 Int54 みたいなものになります。

ですが、Standard MLの固定長整数は2の補数表現を仮定しており、表現できる範囲は\([-2^n,2^n-1]\)の形である必要があります。これとsafe integerを比べると、\(-2^{53}\)がはみ出ます。

なので、LunarMLで Int54 を提供するには、演算結果が\(-(2^{53}+1)\)の場合を何らかの方法で検出し、オーバーフロー例外を起こさなければなりません。この時、\(2^{53}+1\)が素数だったなら乗算の場合に演算結果が\(-(2^{53}+1)\)になる可能性を考慮しなくてよかったのに、現実は残酷でした、という話です。