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

[インデックス 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)のパラメータ順序の誤りを修正するものです。具体的には、abの比較において、本来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コンパイラ内部で多倍長浮動小数点数を表現するために使用される構造体であると推測されます。これは、標準のfloat32float64よりも高い精度で計算を行うために用いられます。
  • mpcmpfltc関数: この関数は、多倍長浮動小数点数adouble型の浮動小数点数cを比較するためのGoコンパイラ内部の関数です。関数名から、mpは多倍長(multiple precision)、cmpは比較(compare)、fltは浮動小数点数(float)、cは定数(constant)またはdouble型を意味すると考えられます。
  • mpcmpfltflt関数: この関数は、2つの多倍長浮動小数点数abを比較するためのGoコンパイラ内部の関数です。この関数が、実際の多倍長浮動小数点数同士の比較ロジックを実装していると考えられます。
  • mpmovecflt関数: この関数は、double型の値を多倍長浮動小数点数型Mpfltに変換(ムーブ)するためのGoコンパイラ内部の関数です。
  • 浮動小数点数比較のセマンティクス: 浮動小数点数の比較は、整数とは異なり、厳密な等価性(a == b)のチェックが難しい場合があります。通常、abの比較は、a - bが0と比較されることで行われます。これは、a > bであればa - b > 0a < bであればa - b < 0a == bであればa - b == 0となるためです。もしb - aと比較してしまうと、比較の大小関係が逆転してしまいます。
  • 定数畳み込み (Constant Folding): コンパイラの最適化手法の一つで、コンパイル時に定数式を評価し、その結果を直接コードに埋め込むことです。例えば、2 + 3という式があれば、コンパイル時に5に評価され、実行時には5という値が直接使用されます。この最適化は、実行時の計算コストを削減し、プログラムのパフォーマンスを向上させます。このコミットのバグは、この定数畳み込みの過程で浮動小数点数の比較が誤っていたために発生したと考えられます。

技術的詳細

このバグは、Goコンパイラのsrc/cmd/gc/mparith1.cファイル内のmpcmpfltc関数に存在していました。この関数は、Mpflt型の多倍長浮動小数点数bdouble型の浮動小数点数cを比較する役割を担っています。

元のコードでは、mpcmpfltc関数内でまずdouble型のcMpflt型のaに変換し、その後mpcmpfltflt(&a, b)を呼び出していました。ここで問題となるのは、mpcmpfltflt関数が内部でa - bのような比較を行っていると仮定した場合、mpcmpfltflt(&a, b)は実質的にc - bを0と比較することになります。

しかし、コミットメッセージによると、本来比較したかったのはa - b(つまり、bcを比較する際にb - c)でした。元のコードのmpcmpfltflt(&a, b)は、acから変換された値)とbを比較しており、これはcbの比較を意味します。もしmpcmpfltflt(X, Y)X - Yを評価する関数であるならば、mpcmpfltflt(&a, b)a - bを評価します。しかし、期待される動作はb - a(つまりb - c)を評価することでした。

この誤ったパラメータ順序により、例えばb < cであるにもかかわらず、mpcmpfltcb > 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)という関数シグネチャにおけるabの比較順序について言及していると解釈できます。mpcmpfltc(Mpflt *b, double c)という実際のシグネチャでは、bcを比較しています。この文脈で「a - b」は「b(第一引数)- c(第二引数)」を意味し、「b - a」は「c(第二引数)- b(第一引数)」を意味すると考えられます。

したがって、修正後のmpcmpfltflt(b, &a)は、bcの差を正しく計算し、その結果を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言語の公式ドキュメント
  • 一般的なコンパイラの最適化(定数畳み込み)に関する情報
  • 浮動小数点数演算の比較に関する情報