[インデックス 1542] ファイルの概要
このコミットは、Go言語の初期開発段階における重要なリファクタリングとアーキテクチャ変更を示しています。主に、浮動小数点演算に関連するルーチンをsys
パッケージからmath
パッケージへ移動し、GoとC言語間のインターフェースにCgoを導入することで、手書きのラッパーを置き換えています。これにより、コードのモジュール性、保守性、そして将来的な拡張性が向上しています。
コミット
commit 1f8a40d85c3bb7a1cf3113e7ab1afdb44f6c0e4d
Author: Russ Cox <rsc@golang.org>
Date: Thu Jan 22 16:23:44 2009 -0800
move math routines from package sys to package math,
though they still build in src/runtime.
use cgo instead of hand-written wrappers.
R=r
DELTA=740 (289 added, 300 deleted, 151 changed)
OCL=23326
CL=23331
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1f8a40d85c3bb7a1cf3113e7ab1afdb44f6c0e4d
元コミット内容
このコミットの元のメッセージは以下の通りです。
「mathルーチンをsys
パッケージからmath
パッケージへ移動。ただし、これらは引き続きsrc/runtime
でビルドされる。手書きのラッパーの代わりにCgoを使用する。」
変更の背景
Go言語の初期段階では、多くの低レベルなシステム関連関数やランタイム内部関数がsys
パッケージに集約されていました。これには、浮動小数点演算に関する関数も含まれていました。しかし、このような設計は、関心の分離の原則に反し、コードの可読性、保守性、そして再利用性を低下させる可能性がありました。
このコミットの主な背景は以下の2点です。
- モジュール性の向上: 浮動小数点演算は一般的な数学操作であり、システムコールやランタイムの内部処理とは異なるドメインに属します。これらを専用の
math
パッケージに分離することで、Go標準ライブラリの構造をより論理的かつ整理されたものにし、開発者が特定の機能を見つけやすく、利用しやすくすることを目指しました。 - Cgoの導入と手書きラッパーの置き換え: Go言語は、C言語で書かれた既存のライブラリと連携するためのメカニズムを必要としていました。初期には手書きのC言語ラッパーやアセンブリコードが使用されることもありましたが、これは開発コストが高く、移植性にも課題がありました。Cgoは、GoコードからC関数を直接呼び出すための公式なツールであり、より安全で効率的な相互運用性を提供します。このコミットは、浮動小数点演算ルーチンにおいてCgoを本格的に採用し、将来的に他のシステムレベルの機能にもCgoを適用するための布石となりました。これにより、GoのランタイムがCライブラリの機能をより柔軟に利用できるようになり、特にOS固有の機能や高性能な数値計算ライブラリとの連携が容易になりました。
前提知識の解説
このコミットを理解するためには、以下の概念が重要です。
- Go言語のパッケージシステム: Go言語は、コードを論理的に分割し、再利用性を高めるためにパッケージシステムを採用しています。
sys
やmath
はGoの標準パッケージの一部です。 - Goランタイム (runtime): Goプログラムの実行を管理する低レベルなコード群です。ガベージコレクション、スケジューリング、システムコールなどが含まれます。Goの標準ライブラリの一部である
math
パッケージの関数であっても、その実装が最終的にランタイム内のCコードに依存することは珍しくありません。 - 浮動小数点演算 (Floating-Point Arithmetic): コンピュータで実数を近似的に表現し、計算するための方法です。IEEE 754標準が広く用いられており、
NaN
(Not a Number) やInf
(Infinity) といった特殊な値も定義されています。これらの特殊な値の扱いも、数学関数の正確性には不可欠です。 - Cgo: Go言語の機能の一つで、GoプログラムからC言語の関数を呼び出したり、C言語のコードをGoプログラムに組み込んだりするためのツールです。Cgoを使用すると、Goのソースファイル内にCコードを直接記述したり、既存のCライブラリをリンクしたりできます。これにより、Go言語だけでは実現が難しい低レベルな操作や、既存の高性能なCライブラリの利用が可能になります。Cgoは、GoとCの間のデータ変換や関数呼び出しの橋渡しを自動的に行います。
- 手書きのラッパー (Hand-written wrappers): Cgoが成熟する以前や、特定のパフォーマンス要件がある場合に、GoとCの間のインターフェースを手動で記述したコードのことです。これには、Goの関数からCの関数を呼び出すためのアセンブリコードや、Goのデータ構造をCのデータ構造に変換するCコードなどが含まれます。Cgoに比べて開発が複雑でエラーを起こしやすく、移植性も低いという欠点があります。
src/cmd/gc
: Goコンパイラ(gc)のソースコードがあるディレクトリです。Goの組み込み関数や型に関する情報が定義されています。sys.go
やsysimport.c
は、コンパイラがGoの組み込み関数を認識するために使用されていました。Makefile
: ビルドプロセスを自動化するためのファイルです。Goの初期のビルドシステムでは、Makefile
が広く使われていました。
技術的詳細
このコミットの技術的な変更は多岐にわたりますが、主要なポイントは以下の通りです。
-
浮動小数点ルーチンの移動:
- これまで
src/runtime/runtime.c
に直接実装されていたfloat32tobits
,float64tobits
,float64frombits
,float32frombits
,isInf
,NaN
,isNaN
,Inf
,frexp
,ldexp
,modf
といった浮動小数点関連のC関数が、新しく作成されたsrc/runtime/float.c
に移動されました。 - これらの関数は、Goの
math
パッケージから利用されることを想定しています。 src/cmd/gc/sys.go
およびsrc/cmd/gc/sysimport.c
から、これらの浮動小数点関連関数の宣言が削除されました。これは、これらの関数がもはやsys
パッケージの組み込み関数として扱われないことを意味します。
- これまで
-
CgoによるGo-Cインターフェースの確立:
- 新しく
src/runtime/float_go.cgo
ファイルが導入されました。このファイルはCgoの構文を使用して、src/runtime/float.c
で定義されたC関数(frexp
,ldexp
,modf
,isInf
,isNaN
,Inf
,NaN
,float32tobits
,float64tobits
,float32frombits
,float64frombits
)をGoのmath
パッケージの関数としてエクスポートしています。 - 同様に、
src/runtime/sema_go.cgo
が導入され、セマフォ関連のC関数(semacquire
,semrelease
)をGoのsync
パッケージに公開しています。 - これにより、GoのコードはCgoを介してこれらの低レベルなC関数を呼び出すことができるようになり、手書きのラッパーが不要になりました。
- 新しく
-
math
パッケージの内部変更:src/lib/math
ディレクトリ内の既存のGoファイル(asin.go
,exp.go
,floor.go
,fmod.go
,log.go
,pow.go
,sin.go
,sqrt.go
,tan.go
など)は、これまでsys.Frexp
やsys.Modf
のようにsys
パッケージの関数を直接参照していた箇所を、Cgoを介して公開されたmath
パッケージ内の同名の関数(例:Frexp()
,Modf()
)に置き換えました。これにより、math
パッケージが自己完結性を高め、外部のsys
パッケージへの依存を減らしました。src/lib/math/Makefile
が大幅に修正され、float.c
とfloat_go.cgo
のコンパイルとリンクが組み込まれました。また、オブジェクトファイルのグループ化(O1
,O2
,O3
,O4
)が再編成され、ビルドの依存関係が更新されました。
-
strconv
パッケージの変更:src/lib/strconv/atof.go
とsrc/lib/strconv/ftoa.go
では、浮動小数点数のビット表現を扱う関数(sys.Float32frombits
,sys.Float64frombits
,sys.Float32bits
,sys.Float64bits
)が、新しくmath
パッケージからインポートされたmath.Float*bits
関数に置き換えられました。これにより、strconv
パッケージもmath
パッケージの新しいインターフェースを利用するようになりました。
-
cgo2c
ツールの改善:src/runtime/cgo2c.c
は、Cgoの処理を行う内部ツールです。このコミットでは、エラーメッセージの改善(ファイル名と行番号の表示)や、コマンドライン引数の解析方法の変更が行われました。これは、Cgoツールの堅牢性を高めるための改善です。
-
セマフォ実装の変更 (Darwin/amd64):
src/runtime/amd64_darwin.h
とsrc/runtime/rt1_amd64_darwin.c
では、Darwin (macOS) 上でのセマフォ関連の関数名がsemcreate
からmach_semcreate
のように変更されました。これは、MachカーネルのセマフォAPIをより明示的に参照するためと考えられます。src/runtime/sema.c
では、Goのsync
パッケージから呼び出されるセマフォ関数(semacquire
,semrelease
)のC実装が、sync·semacquire
からsemacquire
へと名前が変更されました。これは、CgoによってGoから直接呼び出されるC関数としての命名規則に合わせたものと推測されます。
これらの変更は、Go言語の初期設計において、低レベルなランタイム機能と高レベルな標準ライブラリ機能の間の境界を明確にし、Cgoを介したよりクリーンなインターフェースを確立しようとする意図を強く示しています。
コアとなるコードの変更箇所
このコミットのコアとなる変更は、主に以下のファイルに集約されています。
-
src/runtime/float.c
(新規追加):- これまで
src/runtime/runtime.c
に散らばっていた浮動小数点関連のC関数(float32tobits
,float64tobits
,isInf
,NaN
,frexp
,ldexp
,modf
など)がここに集約されました。 - これらの関数は、Goの
math
パッケージが内部的に利用する低レベルな実装を提供します。
- これまで
-
src/runtime/float_go.cgo
(新規追加):- Cgoのディレクティブ(
#include "runtime.h"
)とGoの関数宣言を組み合わせることで、float.c
で定義されたC関数をGoのmath
パッケージの関数として公開しています。 - 例:
このGo関数func Frexp(f float64) (frac float64, exp int32) { frac = frexp(f, &exp); }
Frexp
は、C言語のfrexp
関数を呼び出しています。
- Cgoのディレクティブ(
-
src/runtime/sema_go.cgo
(新規追加):- 同様に、Cgoを使用して
semacquire
とsemrelease
というC関数をGoのsync
パッケージに公開しています。
- 同様に、Cgoを使用して
-
src/runtime/runtime.c
(大幅な削除):float.c
に移動されたすべての浮動小数点関連のC関数がこのファイルから削除されました。これにより、runtime.c
はより純粋なGoランタイムのコア機能に特化するようになりました。
-
src/cmd/gc/sys.go
およびsrc/cmd/gc/sysimport.c
:sys
パッケージから浮動小数点関連の関数宣言が削除されました。これにより、これらの関数はもはやGoコンパイラによってsys
パッケージの組み込み関数として特別扱いされなくなりました。
-
src/lib/math/*.go
ファイル群:sys.Frexp
などのsys
パッケージへの直接的な参照が、math
パッケージ内で定義された(Cgoを介してC実装にルーティングされる)関数に置き換えられました。これにより、math
パッケージのGoコードが、Cgoを介して提供される新しいC実装を利用するようになりました。
コアとなるコードの解説
src/runtime/float.c
このファイルは、Goのmath
パッケージが利用する浮動小数点演算の低レベルなC言語実装を提供します。
例えば、float64tobits
関数は、float64
型の値をそのIEEE 754標準のビット表現(uint64
)に変換します。これは、浮動小数点数の内部構造を直接操作する必要がある場合(例: NaN
やInf
の判定、ビット操作による指数部や仮数部の抽出)に不可欠です。
frexp
、ldexp
、modf
といった関数は、それぞれ浮動小数点数を仮数部と指数部に分解したり、それらを再構築したり、整数部と小数部に分割したりする標準的な数学関数です。これらは、より複雑な数学関数(例: Log
, Exp
, Pow
)の実装の基礎となります。
isInf
, isNaN
, Inf
, NaN
関数は、IEEE 754で定義される無限大や非数といった特殊な浮動小数点値を生成したり、それらを判定したりするためのものです。これらの関数は、数値計算の堅牢性を確保するために重要です。
src/runtime/float_go.cgo
このファイルは、GoとCの間の「橋渡し」の役割を担います。Cgoの構文(#include "runtime.h"
)を使ってCのヘッダーファイルをインクルードし、その後にGoの関数を定義します。これらのGo関数は、Cの関数を呼び出すための薄いラッパーとして機能します。
例えば、func Frexp(f float64) (frac float64, exp int32)
というGoの関数は、内部でCのfrexp
関数を呼び出し、その結果をGoの戻り値として返します。Cgoは、Goのfloat64
型とCのdouble
型、Goのint32
型とCのint32_t
型(または同等の型)の間で自動的に型変換を行います。
このアプローチにより、Goのmath
パッケージは、C言語で最適化されたり、OS固有の機能を利用したりする低レベルな浮動小数点演算を、Goのコードから直接、かつ型安全な方法で利用できるようになります。
src/lib/math/*.go
の変更
これらのファイルでは、これまでsys
パッケージの関数を直接呼び出していた箇所が、math
パッケージ内で定義された(Cgoを介してC実装にルーティングされる)関数に置き換えられました。
例えば、src/lib/math/asin.go
では、sys.NaN()
がNaN()
に、src/lib/math/exp.go
ではsys.IsNaN(x)
がIsNaN(x)
に、sys.Inf(1)
がInf(1)
に、sys.Ldexp(y, k)
がLdexp(y, k)
に変更されています。
これにより、math
パッケージのGoコードは、sys
パッケージという低レベルな依存関係から解放され、よりクリーンな依存関係グラフが構築されました。これは、Goの標準ライブラリの設計原則である「関心の分離」を強化するものです。
これらの変更は、Go言語が初期段階でどのように低レベルなシステム機能と高レベルなライブラリ機能を分離し、Cgoという強力なツールを導入して、より堅牢で保守性の高いコードベースを構築していったかを示す好例です。
関連リンク
- Go言語のCgoに関する公式ドキュメント (現在のもの): https://go.dev/blog/cgo
- Go言語の
math
パッケージに関する公式ドキュメント: https://pkg.go.dev/math - Go言語の
sync
パッケージに関する公式ドキュメント: https://pkg.go.dev/sync
参考にした情報源リンク
- IEEE 754 浮動小数点数標準: https://ja.wikipedia.org/wiki/IEEE_754
- Go言語の初期のコミット履歴 (GitHub): https://github.com/golang/go/commits/master
- Go言語の
sys
パッケージの歴史に関する議論 (Stack Overflowなど、具体的なURLは特定しにくいが、一般的な知識として) - Cgoの内部動作に関する技術記事 (一般的な知識として)