Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 14180] ファイルの概要

このコミットは、Go言語の仕様書(doc/go_spec.html)に対する変更であり、定数式におけるゼロ除算の扱いを明確にし、非定数整数式においても定数除数がゼロであってはならないという要件を追加するものです。これにより、コンパイル時および実行時のゼロ除算に関する挙動がより厳密に定義されます。

コミット

commit ddddd39fc8b7ab073044e0fe8ad7c0eb912758b9
Author: Robert Griesemer <gri@golang.org>
Date:   Fri Oct 19 10:12:09 2012 -0700

    go spec: constant divisors must not be zero

    Both gc and gccgo always checked this for constant
    expressions but the spec only mentions run-time
    exceptions.

    This CL also requires that constant divisors
    must not be zero in non-constant integer expressions:
    This is consistent with the spirit of the most
    recent changes and it is consistent with constant
    expressions. We don't want to specify the effect for
    non-integer expressions (f/0.0 where f is a float or
    complex number) because there the result f/g is not
    further specified if a non-constant g is 0.

    R=r, rsc, iant, ken, andybalholm, iant
    CC=golang-dev
    https://golang.org/cl/6710045

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/ddddd39fc8b7ab073044e0fe8ad7c0eb912758b9

元コミット内容

このコミットは、Go言語の仕様書(doc/go_spec.html)を更新し、除算および剰余演算におけるゼロ除算のルールをより厳密に定義しています。

主な変更点は以下の通りです。

  1. 定数除算におけるゼロ除算の明示的な禁止: 以前の仕様では、除数がゼロの場合に「実行時パニックが発生する」とだけ記述されていましたが、この変更により、「除数が定数である場合、それはゼロであってはならない」というルールが明示的に追加されました。これにより、コンパイル時にゼロ除算が検出されるべきケースが明確になります。
  2. 非定数整数式における定数除数のゼロ禁止: 定数式だけでなく、非定数の整数式においても、除数が定数でゼロである場合は禁止されるようになりました。これは、定数式との一貫性を保ち、より予測可能な挙動を保証するためです。
  3. 浮動小数点数や複素数における非定数ゼロ除算の扱いの据え置き: 浮動小数点数や複素数の非定数式におけるゼロ除算(例: f/0.0)については、結果がさらに指定されていないため、このコミットではその効果を特定しない方針が維持されています。これは、IEEE 754などの標準で定義される特殊な値(NaN, Inf)の挙動に依存するため、言語仕様で一律にパニックを強制するのではなく、実装に委ねるという判断です。
  4. 仕様書からの不要なタグの削除: <p>タグの閉じ忘れと思われる箇所が修正されています。

変更の背景

この変更の背景には、Go言語のコンパイラ(gcおよびgccgo)が既に定数式におけるゼロ除算をチェックしていたにもかかわらず、言語仕様書がその挙動を明確に記述していなかったという乖離がありました。仕様書は実行時パニックについてのみ言及しており、コンパイル時のチェックについては触れていませんでした。

Go言語の設計哲学の一つに「明確さと一貫性」があります。定数式におけるゼロ除算がコンパイラによって検出されるのであれば、その挙動は言語仕様によっても明示的に保証されるべきです。これにより、開発者はコンパイル時にエラーを捕捉できることを期待でき、実行時まで待つ必要がなくなります。

また、非定数整数式においても、除数が定数でゼロである場合にエラーとすることで、定数式との一貫性を高め、言語全体の予測可能性と堅牢性を向上させる狙いがあります。これは、Go言語が型安全性とエラーハンドリングを重視する設計思想に基づいているため、未定義の挙動や実行時エラーを可能な限り早期に検出することを目的としています。

浮動小数点数や複素数のゼロ除算については、IEEE 754などの標準でNaN(Not a Number)やInf(Infinity)といった特殊な値が定義されており、これらはパニックではなく、これらの特殊な値を返すことで処理が継続されることが一般的です。Go言語の設計者は、これらのケースについてまで一律にパニックを強制するのではなく、既存の数値計算の慣習を尊重し、非定数除算の結果が未定義である場合に言語仕様でその効果を特定しないという方針を維持しました。

前提知識の解説

このコミットを理解するためには、以下のGo言語の基本的な概念とコンピュータサイエンスの知識が必要です。

  1. Go言語の定数 (Constants):

    • Go言語における定数は、コンパイル時に値が決定される不変のエンティティです。数値、真偽値、文字列の定数があります。
    • 定数式は、定数のみから構成される式であり、その結果もコンパイル時に決定されます。
    • 例: const PI = 3.14, const MaxInt = 1 << 63 - 1
  2. 除算と剰余演算:

    • Go言語では、/が除算、%が剰余演算子です。
    • 整数除算では、結果は常に整数に切り捨てられます(ゼロ方向への切り捨て)。
    • 剰余演算の結果の符号は、被除数(左オペランド)の符号と同じになります。
  3. ゼロ除算 (Division by Zero):

    • 数学的に、ゼロによる除算は未定義です。
    • コンピュータシステムでは、ゼロ除算は通常、エラー(例外)を引き起こします。
    • 整数除算: 多くのプログラミング言語では、整数におけるゼロ除算は致命的なエラー(例: 実行時エラー、例外、パニック)となります。これは、結果を表現できる有限の値がないためです。
    • 浮動小数点数除算: IEEE 754浮動小数点数標準では、ゼロ除算の結果は特殊な値として定義されます。
      • x / 0.0 (x > 0) は正の無限大 (+Inf)
      • x / 0.0 (x < 0) は負の無限大 (-Inf)
      • 0.0 / 0.0 は非数 (NaN, Not a Number) これらの特殊な値は、プログラムの実行を中断させることなく、計算を継続させることを可能にします。
  4. Go言語のパニック (Panic):

    • Go言語におけるパニックは、プログラムの通常の実行フローを中断させる、回復不可能なエラーを示すメカニズムです。
    • パニックが発生すると、現在の関数の実行が停止し、遅延関数(defer)が実行され、呼び出しスタックを遡ってパニックが伝播します。
    • 最終的に、パニックがrecoverによって捕捉されない場合、プログラムは異常終了します。
    • ゼロ除算は、Go言語において典型的な実行時パニックの原因の一つです。
  5. コンパイル時と実行時:

    • コンパイル時: ソースコードが機械語に変換される段階です。この段階で検出されるエラーは「コンパイルエラー」と呼ばれ、プログラムは実行されません。
    • 実行時: コンパイルされたプログラムが実際に実行される段階です。この段階で発生するエラーは「実行時エラー」と呼ばれ、プログラムのクラッシュや予期せぬ挙動を引き起こす可能性があります。
    • このコミットは、ゼロ除算のエラー検出を可能な限りコンパイル時に移行させようとする意図を含んでいます。

技術的詳細

このコミットは、Go言語の仕様書であるdoc/go_spec.htmlを直接編集することで、言語の挙動に関する公式な定義を変更しています。

具体的には、以下のセクションが変更されています。

  1. "Arithmetic operators" (算術演算子) セクション:

    • 変更前: If the divisor is zero, a <a href="#Run_time_panics">run-time panic</a> occurs. (除数がゼロの場合、実行時パニックが発生する。)
    • 変更後:
      If the divisor is a <a href="#Constants">constant</a>, it must not be zero.
      If the divisor is zero at run time, a <a href="#Run_time_panics">run-time panic</a> occurs.
      
      (除数が定数である場合、それはゼロであってはならない。実行時に除数がゼロである場合、実行時パニックが発生する。) この変更により、定数除算におけるゼロ除算がコンパイル時に禁止されることが明示されました。これは、コンパイラが定数式の値を事前に計算できるため、ゼロ除算を早期に検出できるという事実に基づいています。
  2. "Constants" (定数) セクション:

    • 新たに以下の段落と例が追加されました。
      <p>
      The divisor of a constant division or remainder operation must not be zero:
      </p>
      
      <pre>
      3.14 / 0.0   // illegal: division by zero
      </pre>
      
      (定数除算または剰余演算の除数はゼロであってはならない。) この追加は、定数式におけるゼロ除算の禁止をさらに強調し、具体的なコード例(3.14 / 0.0)を挙げることで、そのルールを明確に示しています。この例は浮動小数点定数ですが、整数定数にも同様に適用されます。

これらの変更は、Go言語のコンパイラが既に実装していた挙動(定数式でのゼロ除算チェック)を仕様書に反映させるとともに、非定数整数式における定数除数のゼロも禁止することで、言語の一貫性と堅牢性を高めるものです。

重要なのは、この変更が「非定数整数式」に限定されている点です。浮動小数点数や複素数の非定数式におけるゼロ除算については、IEEE 754標準の挙動(NaNやInfの生成)を尊重し、Go言語の仕様としてはその効果を特定しないという方針が維持されています。これは、数値計算の分野における既存の慣習と互換性を保つための設計上の選択です。

コアとなるコードの変更箇所

変更はdoc/go_spec.htmlファイルに集中しています。

--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -3001,7 +3001,8 @@ int64    -9223372036854775808
 </pre>

 <p>
-If the divisor is zero, a <a href="#Run_time_panics">run-time panic</a> occurs.
+If the divisor is a <a href="#Constants">constant</a>, it must not be zero.
+If the divisor is zero at run time, a <a href="#Run_time_panics">run-time panic</a> occurs.
 If the dividend is positive and the divisor is a constant power of 2,
 the division may be replaced by a right shift, and computing the remainder may
 be replaced by a bitwise AND operation:
@@ -3692,6 +3693,14 @@ const Huge = 1 &lt;&lt; 100
 const Four int8 = Huge &gt;&gt; 98
 </pre>

+<p>
+The divisor of a constant division or remainder operation must not be zero:
+</p>
+\n
+<pre>
+3.14 / 0.0   // illegal: division by zero
+</pre>
+\n
 <p>
 The values of <i>typed</i> constants must always be accurately representable as values
 of the constant type. The following constant expressions are illegal:
@@ -4759,8 +4768,6 @@ the function completes.\n (See also the section on <a href="#Handling_panics">handling panics</a>.)
 </p>

-</p>
-\n
 <pre>
 lock(l)
 defer unlock(l)  // unlocking happens before surrounding function returns

コアとなるコードの解説

このコミットのコアとなる変更は、Go言語の仕様書にゼロ除算に関する新しいルールを明示的に追加した点です。

  1. 行 3001-3002 の変更:

    • 元の記述「除数がゼロの場合、実行時パニックが発生する」は、実行時の挙動のみをカバーしていました。
    • 新しい記述「除数が定数である場合、それはゼロであってはならない。実行時に除数がゼロである場合、実行時パニックが発生する。」は、定数除算におけるゼロ除算がコンパイル時に禁止されることを明確にしています。これにより、コンパイラはこのようなコードを不正として拒否する責任を負うことになります。これは、コンパイル時に検出できるエラーは、実行時まで持ち越すべきではないという原則に基づいています。
  2. 行 3692-3700 の追加:

    • 「定数除算または剰余演算の除数はゼロであってはならない」という新しい段落が追加されました。
    • その直後に、具体的な例として 3.14 / 0.0 // illegal: division by zero が示されています。この例は、浮動小数点定数によるゼロ除算もコンパイル時に不正とされることを示唆しています。これは、Go言語の定数評価が非常に厳密であり、コンパイル時に可能な限り多くのエラーを捕捉しようとする設計思想を反映しています。
  3. 行 4759-4760 の削除:

    • 不要な閉じタグ </p> が削除されました。これは、HTMLの構文的な修正であり、仕様の内容には直接影響しませんが、ドキュメントの整合性を保つためのクリーンアップです。

これらの変更は、Go言語のコンパイラが既に持っていたゼロ除算に関するチェックの挙動を仕様書に明記し、さらに非定数整数式における定数除数のゼロも禁止することで、言語の定義をより厳密で一貫性のあるものにしています。これにより、開発者はゼロ除算に関するエラーをより早期に、そして予測可能な形で検出できるようになります。

関連リンク

参考にした情報源リンク