[インデックス 18008] ファイルの概要
コミット
commit f85ba7d50a7df5a978a259a3e06bc30af1bbd5df
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Mon Dec 16 16:54:10 2013 -0500
cmd/gc: fix comparison order of parameters in mpcmpfltc(a, b)
It should compare a - b to 0, not b - a to 0.
Fixes #6964.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/39020044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f85ba7d50a7df5a978a259a3e06bc30af1bbd5df
元コミット内容
cmd/gc: fix comparison order of parameters in mpcmpfltc(a, b)
It should compare a - b to 0, not b - a to 0.
Fixes #6964.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/39020044
変更の背景
このコミットは、Goコンパイラ(cmd/gc
)における浮動小数点数比較関数mpcmpfltc(a, b)
のパラメータ順序の誤りを修正するものです。具体的には、a
とb
の比較において、本来a - b
が0と比較されるべきところを、誤ってb - a
が0と比較されていたという問題に対処しています。
この問題は、Goコンパイラが定数式を評価する際に、浮動小数点数の比較が正しく行われない場合に、予期せぬコンパイルエラーや不正なコード生成を引き起こす可能性がありました。コミットメッセージにあるFixes #6964
は、このバグがGoのIssueトラッカーで報告されていたことを示しています。test/fixedbugs/issue6964.go
という新しいテストファイルが追加されていることから、このバグが特定の定数式評価で発生していたことが伺えます。特に、_ = string(-4 + 2i + 2)
というコードがエラーを発生させていたことから、複素数と実数の混合演算における浮動小数点数比較のロジックに問題があったと考えられます。
前提知識の解説
- Goコンパイラ (
cmd/gc
): Go言語の公式コンパイラです。Goのソースコードを機械語に変換する役割を担っています。src/cmd/gc
ディレクトリにそのソースコードが格納されています。 - 多倍長浮動小数点数演算 (MPFR/GMPライブラリの概念): Goコンパイラは、コンパイル時に定数式を評価する際に、高い精度が要求される浮動小数点数演算のために、多倍長精度演算ライブラリの概念を使用しています。
mpflt
という型は、Goコンパイラ内部で多倍長浮動小数点数を表現するために使用される構造体であると推測されます。これは、標準のfloat32
やfloat64
よりも高い精度で計算を行うために用いられます。 mpcmpfltc
関数: この関数は、多倍長浮動小数点数a
とdouble
型の浮動小数点数c
を比較するためのGoコンパイラ内部の関数です。関数名から、mp
は多倍長(multiple precision)、cmp
は比較(compare)、flt
は浮動小数点数(float)、c
は定数(constant)またはdouble
型を意味すると考えられます。mpcmpfltflt
関数: この関数は、2つの多倍長浮動小数点数a
とb
を比較するためのGoコンパイラ内部の関数です。この関数が、実際の多倍長浮動小数点数同士の比較ロジックを実装していると考えられます。mpmovecflt
関数: この関数は、double
型の値を多倍長浮動小数点数型Mpflt
に変換(ムーブ)するためのGoコンパイラ内部の関数です。- 浮動小数点数比較のセマンティクス: 浮動小数点数の比較は、整数とは異なり、厳密な等価性(
a == b
)のチェックが難しい場合があります。通常、a
とb
の比較は、a - b
が0と比較されることで行われます。これは、a > b
であればa - b > 0
、a < b
であればa - b < 0
、a == b
であればa - b == 0
となるためです。もしb - a
と比較してしまうと、比較の大小関係が逆転してしまいます。 - 定数畳み込み (Constant Folding): コンパイラの最適化手法の一つで、コンパイル時に定数式を評価し、その結果を直接コードに埋め込むことです。例えば、
2 + 3
という式があれば、コンパイル時に5
に評価され、実行時には5
という値が直接使用されます。この最適化は、実行時の計算コストを削減し、プログラムのパフォーマンスを向上させます。このコミットのバグは、この定数畳み込みの過程で浮動小数点数の比較が誤っていたために発生したと考えられます。
技術的詳細
このバグは、Goコンパイラのsrc/cmd/gc/mparith1.c
ファイル内のmpcmpfltc
関数に存在していました。この関数は、Mpflt
型の多倍長浮動小数点数b
とdouble
型の浮動小数点数c
を比較する役割を担っています。
元のコードでは、mpcmpfltc
関数内でまずdouble
型のc
をMpflt
型のa
に変換し、その後mpcmpfltflt(&a, b)
を呼び出していました。ここで問題となるのは、mpcmpfltflt
関数が内部でa - b
のような比較を行っていると仮定した場合、mpcmpfltflt(&a, b)
は実質的にc - b
を0と比較することになります。
しかし、コミットメッセージによると、本来比較したかったのはa - b
(つまり、b
とc
を比較する際にb - c
)でした。元のコードのmpcmpfltflt(&a, b)
は、a
(c
から変換された値)とb
を比較しており、これはc
とb
の比較を意味します。もしmpcmpfltflt(X, Y)
がX - Y
を評価する関数であるならば、mpcmpfltflt(&a, b)
はa - b
を評価します。しかし、期待される動作はb - a
(つまりb - c
)を評価することでした。
この誤ったパラメータ順序により、例えばb < c
であるにもかかわらず、mpcmpfltc
がb > c
であると誤って判断するようなケースが発生し、定数畳み込みの段階で不正な結果が生成される可能性がありました。issue6964.go
のテストケース_ = string(-4 + 2i + 2)
は、複素数と実数の混合演算において、このような浮動小数点数比較の誤りが顕在化した具体的な例であると考えられます。Go言語では、コンパイル時に定数式が評価されるため、このようなコンパイラ内部のバグが直接ユーザーコードの挙動に影響を与えます。
コアとなるコードの変更箇所
変更はsrc/cmd/gc/mparith1.c
ファイルにあります。
--- a/src/cmd/gc/mparith1.c
+++ b/src/cmd/gc/mparith1.c
@@ -65,7 +65,7 @@ mpcmpfltc(Mpflt *b, double c)
Mpflt a;
mpmovecflt(&a, c);
- return mpcmpfltflt(&a, b);
+ return mpcmpfltflt(b, &a);
}
void
また、このバグを修正したことを確認するための新しいテストファイルtest/fixedbugs/issue6964.go
が追加されています。
// errorcheck
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
func main() {
_ = string(-4 + 2i + 2) // ERROR "-4\\+2i"
}
コアとなるコードの解説
変更の中心は、mpcmpfltc
関数内のmpcmpfltflt
関数の呼び出し部分です。
変更前:
return mpcmpfltflt(&a, b);
ここでは、double c
から変換されたMpflt a
が第一引数に、元のMpflt b
が第二引数に渡されていました。もしmpcmpfltflt(X, Y)
がX - Y
を計算する関数であるならば、これはa - b
、すなわちc - b
を評価していました。
変更後:
return mpcmpfltflt(b, &a);
修正後は、元のMpflt b
が第一引数に、double c
から変換されたMpflt a
が第二引数に渡されています。これにより、mpcmpfltflt(b, &a)
はb - a
、すなわちb - c
を評価するようになります。
コミットメッセージの「It should compare a - b to 0, not b - a to 0.」という記述は、mpcmpfltc(a, b)
という関数シグネチャにおけるa
とb
の比較順序について言及していると解釈できます。mpcmpfltc(Mpflt *b, double c)
という実際のシグネチャでは、b
とc
を比較しています。この文脈で「a - b」は「b
(第一引数)- c
(第二引数)」を意味し、「b - a」は「c
(第二引数)- b
(第一引数)」を意味すると考えられます。
したがって、修正後のmpcmpfltflt(b, &a)
は、b
とc
の差を正しく計算し、その結果を0と比較することで、期待される比較結果を返すようになります。これにより、Goコンパイラが定数式を評価する際の浮動小数点数比較のロジックが正しくなり、issue6964
で報告されたバグが解消されました。
追加されたtest/fixedbugs/issue6964.go
は、errorcheck
ディレクティブを使用しており、指定された行で期待されるエラーメッセージが出力されることを検証します。_ = string(-4 + 2i + 2)
という式は、Goの型システムにおいて不正な変換であり、コンパイル時にエラーとなるべきものです。このテストは、このコミットの修正によって、コンパイラがこのような不正な定数式を正しく検出し、適切なエラーメッセージを生成できるようになったことを確認するために追加されました。
関連リンク
- Go言語のIssueトラッカー (GoのIssue #6964は古い情報のため、現在のIssueトラッカーでは直接見つからない可能性がありますが、GoのIssueは通常https://github.com/golang/go/issuesで管理されています。)
- Go言語のコンパイラに関するドキュメント (公式ドキュメントやGoのソースコード内のコメントを参照)
参考にした情報源リンク
- Go言語のソースコード (
src/cmd/gc/mparith1.c
,test/fixedbugs/issue6964.go
) - Go言語の公式ドキュメント
- 一般的なコンパイラの最適化(定数畳み込み)に関する情報
- 浮動小数点数演算の比較に関する情報