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

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

このコミットは、Go言語の標準ライブラリmathパッケージ内の複数の関数(Acosh, Asinh, Atanh, Ceil, Floor, Trunc, Mod, Remainder)における特殊な浮動小数点数の引数と結果に関するドキュメントを拡充するものです。具体的には、NaN (Not a Number)、Inf (Infinity)、±0 (符号付きゼロ) といった非有限な値が関数の入力または出力となる場合の挙動が明確化されています。

コミット

commit 94b0342f17eece0287601918526351733e8b29c4
Author: Charles L. Dorian <cldorian@gmail.com>
Date:   Thu Dec 8 17:07:13 2011 -0500

    math: document more special cases
    
    Acosh, Asinh, Atanh, Ceil, Floor, Trunc, Mod and Remainder affected. These changes add some non-finite arguments and results (and -0.0 results).
    
    R=rsc, golang-dev
    CC=golang-dev
    https://golang.org/cl/5469046

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

https://github.com/golang/go/commit/94b0342f17eece0287601918526351733e8b29c4

元コミット内容

math: document more special cases

Acosh, Asinh, Atanh, Ceil, Floor, Trunc, Mod and Remainder affected. These changes add some non-finite arguments and results (and -0.0 results).

R=rsc, golang-dev CC=golang-dev https://golang.org/cl/5469046

変更の背景

浮動小数点演算においては、通常の数値だけでなく、NaN (Not a Number)、+Inf (正の無限大)、-Inf (負の無限大)、+0.0 (正のゼロ)、-0.0 (負のゼロ) といった特殊な値が存在します。これらの特殊な値が関数の引数として与えられた場合や、計算結果として生成される場合の挙動は、IEEE 754浮動小数点標準によって厳密に定義されています。

Go言語のmathパッケージは、これらの標準に準拠した数学関数を提供していますが、初期の実装では、一部の関数のドキュメントにおいて、これらの特殊なケースに関する記述が不足していました。ドキュメントが不完全であると、開発者がこれらの関数を扱う際に、予期せぬ挙動に遭遇したり、正確なエラーハンドリングや境界条件の考慮が難しくなったりする可能性があります。

このコミットの目的は、mathパッケージ内の主要な数学関数について、IEEE 754標準で定められた特殊な引数と結果の挙動を明示的にドキュメントに追加することで、APIの明確性を高め、開発者がより堅牢なコードを書けるようにすることです。特に、ModRemainderのような関数では、以前は「xが有限でない場合、NaNを返す」といった一般的な記述だったものが、より具体的な無限大やゼロのケースに細分化されています。また、Nextafter関数における-0.0の挙動の明記も、浮動小数点数の厳密な比較や処理において重要です。

前提知識の解説

浮動小数点数とIEEE 754標準

コンピュータにおける浮動小数点数は、実数を近似的に表現するための形式です。Go言語のfloat64型は、IEEE 754倍精度浮動小数点数標準に準拠しています。この標準は、数値の表現方法だけでなく、特殊な値(NaN, Inf, 符号付きゼロ)の定義や、それらを含む演算の結果についても厳密に規定しています。

  • NaN (Not a Number): 不定形な演算結果(例: 0/0, Inf - Inf, Inf * 0, sqrt(-1))や、不正な入力(例: log(-1))によって生成される特殊な値です。NaNは、いかなる値(NaN自身を含む)とも等しくありません。
  • Inf (Infinity): オーバーフロー(例: 1/0)によって生成される無限大を表す値です。+Inf-Infがあります。
  • 符号付きゼロ (+0.0, -0.0): ゼロは正と負の符号を持つことができます。これは、極限の概念や、特定の数値演算(例: 1 / +0.0 = +Inf, 1 / -0.0 = -Inf)において重要になります。通常、+0.0 == -0.0は真ですが、一部の関数やビット表現では区別されます。

双曲線関数

  • Acosh (逆双曲線余弦): arccosh(x) とも書かれ、cosh(y) = x となる y の値です。定義域は x >= 1 です。
  • Asinh (逆双曲線正弦): arcsinh(x) とも書かれ、sinh(y) = x となる y の値です。定義域は全ての実数です。
  • Atanh (逆双曲線正接): arctanh(x) とも書かれ、tanh(y) = x となる y の値です。定義域は -1 < x < 1 です。

丸め関数

  • Floor: 与えられた数値以下の最大の整数を返します(床関数)。例: Floor(3.7) = 3.0, Floor(-3.7) = -4.0
  • Ceil: 与えられた数値以上の最小の整数を返します(天井関数)。例: Ceil(3.7) = 4.0, Ceil(-3.7) = -3.0
  • Trunc: 与えられた数値の小数部を切り捨てて整数部を返します(ゼロ方向への丸め)。例: Trunc(3.7) = 3.0, Trunc(-3.7) = -3.0

剰余関数

  • Mod: x - y * Floor(x/y) として定義される剰余を計算します。結果の符号は x と同じになります。
  • Remainder: IEEE 754標準で定義される剰余演算 x - y * Round(x/y) を計算します。ここで Round は最も近い整数への丸め(同値の場合は偶数へ)です。結果の符号は x と同じになります。

Nextafter関数

  • Nextafter(x, y): x から y の方向へ向かって、x の次に表現可能な浮動小数点数を返します。これは、浮動小数点数の精度や隣接する値を調べる際に使用されます。

技術的詳細

このコミットは、Go言語のmathパッケージ内の各関数のドキュメントコメントに、IEEE 754浮動小数点標準で規定されている特殊なケースの挙動を追記することで、APIの仕様をより明確にしています。

具体的には、以下の関数にドキュメントの変更が加えられました。

  • Acosh(x float64) float64:
    • Acosh(+Inf) = +Inf のケースが追加されました。これは、x が正の無限大に近づくにつれて、Acosh(x) も正の無限大に発散するという数学的性質を反映しています。
  • Asinh(x float64) float64:
    • Asinh(±0) = ±0 のケースが追加されました。双曲線正弦関数は原点を通る奇関数であり、sinh(0) = 0 であるため、その逆関数も 00 にマッピングし、符号を保持します。
  • Atanh(x float64) float64:
    • Atanh(±0) = ±0 のケースが追加されました。tanh(0) = 0 であり、逆関数も符号を保持します。
    • Atanh(x) = NaN if x < -1 or x > 1 の記述が、既存の Atanh(1) = +Inf および Atanh(-1) = -Inf の記述と整合するように再配置されました。これは、Atanh の定義域が (-1, 1) であることを強調しています。
  • Floor(x float64) float64, Ceil(x float64) float64, Trunc(x float64) float64:
    • これら3つの丸め関数すべてに (±0) = ±0 のケースが追加されました。ゼロは整数であるため、これらの関数を適用してもゼロのままですが、符号は保持されます。
  • Mod(x, y float64) float64:
    • 以前の一般的な記述「if x is not finite, Mod returns NaN」および「if y is 0 or NaN, Mod returns NaN」が、より詳細なケースに分割されました。
    • Mod(±Inf, y) = NaN: x が無限大の場合、剰余は不定となります。
    • Mod(NaN, y) = NaN: x がNaNの場合、結果もNaNです。
    • Mod(x, 0) = NaN: y がゼロの場合、ゼロ除算となりNaNです。
    • Mod(x, ±Inf) = x: y が無限大の場合、x/y はゼロに近づくため、剰余は x そのものになります。
    • Mod(x, NaN) = NaN: y がNaNの場合、結果もNaNです。
  • Nextafter(x, y float64) (r float64):
    • Nextafter(0, y) = -0, if y < 0 のケースが追加されました。これは、0 から負の方向へ進む場合に、+0.0 の次に表現可能な値が -0.0 であることを明示しています。
  • Remainder(x, y float64) float64:
    • Mod 関数と同様に、以前の一般的な記述がより詳細なケースに分割されました。
    • Remainder(±Inf, y) = NaN: x が無限大の場合、剰余は不定となります。
    • Remainder(NaN, y) = NaN: x がNaNの場合、結果もNaNです。
    • Remainder(x, 0) = NaN: y がゼロの場合、ゼロ除算となりNaNです。
    • Remainder(x, ±Inf) = x: y が無限大の場合、x/y はゼロに近づくため、剰余は x そのものになります。
    • Remainder(x, NaN) = NaN: y がNaNの場合、結果もNaNです。

これらの変更は、関数の実際の動作を変更するものではなく、Go言語のmathパッケージがIEEE 754標準に準拠していることをドキュメントレベルで明確にし、開発者がこれらの関数の挙動をより正確に理解できるようにすることを目的としています。特に、浮動小数点数の特殊な値の取り扱いは、数値計算の正確性と堅牢性を確保する上で非常に重要です。

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

このコミットは、Go言語のsrc/pkg/mathディレクトリ内の以下のファイルのドキュメントコメントに影響を与えています。

  • src/pkg/math/acosh.go
  • src/pkg/math/asinh.go
  • src/pkg/math/atanh.go
  • src/pkg/math/floor.go
  • src/pkg/math/mod.go
  • src/pkg/math/nextafter.go
  • src/pkg/math/remainder.go

具体的な変更は、各関数のドキュメントブロック内の「Special cases are:」セクションに、新たな特殊ケースの記述を追加または修正する形で行われています。

src/pkg/math/acosh.go

--- a/src/pkg/math/acosh.go
+++ b/src/pkg/math/acosh.go
@@ -36,6 +36,7 @@ package math
 // Acosh(x) calculates the inverse hyperbolic cosine of x.
 //
 // Special cases are:
+//	Acosh(+Inf) = +Inf
 //	Acosh(x) = NaN if x < 1
 //	Acosh(NaN) = NaN
 func Acosh(x float64) float64 {

src/pkg/math/asinh.go

--- a/src/pkg/math/asinh.go
+++ b/src/pkg/math/asinh.go
@@ -33,6 +33,7 @@ package math
 // Asinh(x) calculates the inverse hyperbolic sine of x.
 //
 // Special cases are:
+//	Asinh(±0) = ±0
 //	Asinh(±Inf) = ±Inf
 //	Asinh(NaN) = NaN
 func Asinh(x float64) float64 {

src/pkg/math/atanh.go

--- a/src/pkg/math/atanh.go
+++ b/src/pkg/math/atanh.go
@@ -39,9 +39,10 @@ package math
 // Atanh(x) calculates the inverse hyperbolic tangent of x.
 //
 // Special cases are:
-//	Atanh(x) = NaN if x < -1 or x > 1
 //	Atanh(1) = +Inf
+//	Atanh(±0) = ±0
 //	Atanh(-1) = -Inf
+//	Atanh(x) = NaN if x < -1 or x > 1
 //	Atanh(NaN) = NaN
 func Atanh(x float64) float64 {
  	const NearZero = 1.0 / (1 << 28) // 2**-28

src/pkg/math/floor.go

--- a/src/pkg/math/floor.go
+++ b/src/pkg/math/floor.go
@@ -7,6 +7,7 @@ package math
 // Floor returns the greatest integer value less than or equal to x.
 //
 // Special cases are:
+//	Floor(±0) = ±0
 //	Floor(±Inf) = ±Inf
 //	Floor(NaN) = NaN
 func Floor(x float64) float64 {
@@ -29,6 +30,7 @@ func Floor(x float64) float64 {
 // Ceil returns the least integer value greater than or equal to x.
 //
 // Special cases are:
+//	Ceil(±0) = ±0
 //	Ceil(±Inf) = ±Inf
 //	Ceil(NaN) = NaN
 func Ceil(x float64) float64 { return -Floor(-x) }
@@ -36,6 +38,7 @@ func Ceil(x float64) float64 { return -Floor(-x) }\n // Trunc returns the integer value of x.\n //\n // Special cases are:\n+//	Trunc(±0) = ±0
 //	Trunc(±Inf) = ±Inf
 //	Trunc(NaN) = NaN
 func Trunc(x float64) float64 {

src/pkg/math/mod.go

--- a/src/pkg/math/mod.go
+++ b/src/pkg/math/mod.go
@@ -13,8 +13,11 @@ package math
 // sign agrees with that of x.\n //\n // Special cases are:\n-//	if x is not finite, Mod returns NaN\n-//	if y is 0 or NaN, Mod returns NaN\n+//	Mod(±Inf, y) = NaN\n+//	Mod(NaN, y) = NaN\n+//	Mod(x, 0) = NaN\n+//	Mod(x, ±Inf) = x\n+//	Mod(x, NaN) = NaN
 func Mod(x, y float64) float64 {
  	// TODO(rsc): Remove manual inlining of IsNaN, IsInf
  	// when compiler does it for us.

src/pkg/math/nextafter.go

--- a/src/pkg/math/nextafter.go
+++ b/src/pkg/math/nextafter.go
@@ -10,6 +10,7 @@ package math
 // Special cases are:\n //	Nextafter(NaN, y) = NaN\n //	Nextafter(x, NaN) = NaN\n+//	Nextafter(0, y) = -0, if y < 0
 func Nextafter(x, y float64) (r float64) {
  	// TODO(rsc): Remove manual inlining of IsNaN
  	// when compiler does it for us

src/pkg/math/remainder.go

--- a/src/pkg/math/remainder.go
+++ b/src/pkg/math/remainder.go
@@ -29,11 +29,11 @@ package math
 // Remainder returns the IEEE 754 floating-point remainder of x/y.\n //\n // Special cases are:\n-//	Remainder(x, NaN) = NaN\n+//	Remainder(±Inf, y) = NaN\n //	Remainder(NaN, y) = NaN\n-//	Remainder(Inf, y) = NaN\n //	Remainder(x, 0) = NaN\n-//	Remainder(x, Inf) = x\n+//	Remainder(x, ±Inf) = x\n+//	Remainder(x, NaN) = NaN
 func Remainder(x, y float64) float64 {
  	const (\n  	Tiny    = 4.45014771701440276618e-308 // 0x0020000000000000

コアとなるコードの解説

このコミットは、Go言語のmathパッケージ内の関数の実装コード自体には変更を加えていません。変更はすべて、各関数のドキュメントコメント、特に「Special cases are:」セクションに集中しています。

Go言語では、関数のドキュメントはGoDocツールによって自動生成され、開発者がAPIの挙動を理解するための重要な情報源となります。このコミットは、そのドキュメントの品質と網羅性を向上させることを目的としています。

例えば、Acosh関数のドキュメントでは、以前は Acosh(x) = NaN if x < 1Acosh(NaN) = NaN のみが記載されていましたが、このコミットによって Acosh(+Inf) = +Inf という重要な特殊ケースが追加されました。これは、Acosh関数の実装が既にこの挙動を正しく処理していることを前提としており、その挙動を明示的にドキュメントに反映させたものです。

同様に、Mod関数やRemainder関数では、以前は「xが有限でない場合、NaNを返す」といった抽象的な記述でしたが、このコミットにより、Mod(±Inf, y) = NaNMod(x, 0) = NaN のように、より具体的な引数の組み合わせと結果が列挙されるようになりました。これにより、開発者はこれらの関数が特定の非有限な入力に対してどのように振る舞うかを、より正確に予測できるようになります。

これらのドキュメントの更新は、Go言語の標準ライブラリが、IEEE 754浮動小数点標準の複雑な側面を正確に扱い、その挙動を開発者に明確に伝えることの重要性を示しています。これにより、Go言語で数値計算を行うアプリケーションの信頼性と堅牢性が向上します。

関連リンク

参考にした情報源リンク