[インデックス 1047] ファイルの概要
このコミットは、Go言語の初期段階における任意精度演算ライブラリであるbignum
パッケージの改善に関するものです。主に、文字列から数値への変換機能の強化と、コードベースの整形(末尾のタブの削除)が行われています。
コミット
commit e2fe2f3f23a1029d185fd2fe360f10946fed1c0e
Author: Robert Griesemer <gri@golang.org>
Date: Tue Nov 4 11:37:19 2008 -0800
- better support for string conversions
- removed trailing tabs
R=r
OCL=18458
CL=18458
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e2fe2f3f23a1029d185fd2fe360f10946fed1c0e
元コミット内容
- better support for string conversions
- removed trailing tabs
R=r
OCL=18458
CL=18458
変更の背景
このコミットが行われた2008年11月は、Go言語がまだ一般に公開される前の非常に初期の段階でした。usr/gri/bignum
というパスは、Go言語の共同設計者の一人であるRobert Griesemer氏が個人的に、あるいは実験的に開発していたパッケージであることを示唆しています。
任意精度演算ライブラリにおいて、文字列と数値の間の変換は非常に重要な機能です。ユーザーが数値を入力したり、計算結果を表示したりする際に、この変換が正確かつ柔軟に行える必要があります。特に、異なる基数(2進数、8進数、10進数、16進数など)での表現や、分数、小数点を含む数値のパースは、ライブラリの利便性と実用性を大きく左右します。
このコミットは、bignum
パッケージがより多様な文字列形式をサポートし、変換処理の堅牢性を高めることを目的としています。また、コードベース全体で末尾のタブを削除する変更は、コードの整形と一貫性を保つための一般的なプラクティスであり、将来的なメンテナンス性を向上させるためのものです。
前提知識の解説
-
任意精度演算 (Arbitrary-Precision Arithmetic): コンピュータの標準的なデータ型(例: 64ビット整数や倍精度浮動小数点数)では表現しきれない、非常に大きな整数や、小数点以下が無限に続くような有理数を正確に扱うための数学的演算手法です。Go言語の標準ライブラリには
math/big
パッケージとして提供されていますが、このコミットはそれ以前の、おそらくプロトタイプ段階のbignum
パッケージに関するものです。金融計算、暗号化、科学技術計算など、高い精度が要求される分野で利用されます。 -
基数変換 (Base Conversion): 数値を異なる基数(底)で表現することです。例えば、10進数の「10」は、2進数では「1010」、8進数では「12」、16進数では「A」と表現されます。プログラミングにおいては、文字列から数値をパースする際に、
0x
(16進数)、0
(8進数)などのプレフィックスによって基数を自動判別する機能がよく用いられます。 -
有理数 (Rational Numbers): 整数
a
とゼロではない整数b
を用いてa/b
の形式で表せる数です。例えば、1/2, 3/4, -5/3 などがあります。任意精度演算ライブラリでは、浮動小数点数(精度に限界がある)の代わりに有理数を用いて、計算結果の精度を完全に保つことがあります。このコミットでは、RatFromString
関数が分数形式(例: "1/2")だけでなく、小数点形式(例: "3.14")も有理数としてパースする機能が追加されています。小数点形式の数値は、例えば "3.14" であれば "314/100" のように有理数に変換されます。
技術的詳細
このコミットにおける主要な技術的変更点は以下の通りです。
-
FromString
関数の戻り値の変更:bignum
パッケージ内のNatFromString
(自然数)、IntFromString
(整数)、RatFromString
(有理数)の各関数は、文字列から数値をパースする際に、パースされた数値オブジェクトに加えて、実際に使用された基数(uint
型)を返すようにシグネチャが変更されました。 変更前:func NatFromString(s string, base uint, slen *int) *Natural
変更後:func NatFromString(s string, base uint, slen *int) (*Natural, uint)
この変更により、呼び出し元は、base
引数が0
(基数自動判別)であった場合に、実際にどの基数で文字列が解釈されたかを知ることができるようになり、より柔軟な処理が可能になります。 -
RatFromString
の機能拡張(小数点形式のサポート):RatFromString
関数は、従来の分数形式(例:"1/2"
)の文字列だけでなく、小数点形式(例:"3.14"
)の文字列も有理数としてパースできるようになりました。- 文字列中に
/
(スラッシュ)があれば分数として、.
(ピリオド)があれば小数点形式として解釈されます。 - 小数点形式
X.Y
の場合、X
を整数部、Y
を小数部としてパースし、Y
の桁数に基づいてBase^len(Y)
を分母とする有理数に変換されます。 例えば、10進数で"3.14"
は314/100
として、2進数で"101.01"
は101_2 + 01_2 / 2^2 = 5 + 1/4 = 21/4
として解釈されます。 - この変換は、整数部と小数部をそれぞれパースし、小数部を
Base
のべき乗で割ることで行われます。具体的には、a = MakeInt(a.sign, a.mant.Mul(f).Add(b));
とb = f;
の行がこのロジックを実装しており、f
はBase
の小数部の桁数乗(例: 10進数で小数部が2桁なら10^2=100
)に相当します。
- 文字列中に
-
テストコードの変更 (
bignum_test.go
):bignum_test.go
ファイルでは、Big.NatFromString
などの新しいシグネチャを持つ関数を呼び出すためのラッパー関数(例:func NatFromString(s string, base uint, slen *int) *Big.Natural
)が導入されました。これにより、既存のテストコードが新しい戻り値(基数)を無視して引き続き動作するように互換性が保たれています。RatConv()
テストケースが拡張され、小数点形式の文字列からの有理数変換が正しく行われることを検証する新しいテストが追加されました。これにより、新機能の正確性が保証されます。
-
末尾のタブの削除:
bignum.go
ファイル内の複数の行で、行末に存在していた不要なタブ文字が削除されました。これはコードの整形に関する変更であり、コードの可読性を向上させ、バージョン管理システムでの差分表示をよりクリーンにするための一般的なコードスタイル改善です。
コアとなるコードの変更箇所
usr/gri/bignum/bignum.go
--- a/usr/gri/bignum/bignum.go
+++ b/usr/gri/bignum/bignum.go
@@ -180,7 +180,7 @@ func Mul11(x, y Digit) (Digit, Digit) {
// z = z1*B + z0 = x*y
z0 := (t1<<W2 + t0)&M;
z1 := t2<<DW + (t1 + t0>>W2)>>(W-W2);
-
+
return z1, z0;
}
@@ -453,17 +453,17 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) {
assert(n+1 <= cap(x)); // space for one extra digit
x = x[0 : n + 1];
assert(x[n] == 0);
-
+
if m == 1 {
// division by single digit
// result is shifted left by 1 in place!
x[0] = Div1(x[1 : n+1], x[0 : n], y[0]);
-
+
} else if m > n {
// y > x => quotient = 0, remainder = x
// TODO in this case we shouldn't even unpack x and y
m = n;
-
+
} else {
// general case
assert(2 <= m && m <= n);
@@ -478,12 +478,12 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) {
Mul1(y, y, Digit2(f));
}
assert(B2/2 <= y[m-1] && y[m-1] < B2); // incorrect scaling
-
+
y1, y2 := Digit(y[m-1]), Digit(y[m-2]);
d2 := Digit(y1)<<W2 + Digit(y2);
for i := n-m; i >= 0; i-- {
k := i+m;
-
+
// compute trial digit (Knuth)
var q Digit;
{x0, x1, x2 := Digit(x[k]), Digit(x[k-1]), Digit(x[k-2]);
@@ -496,14 +496,14 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) {
q--
}
}
-
+
// subtract y*q
c := Digit(0);
for j := 0; j < m; j++ {
t := c + Digit(x[i+j]) - Digit(y[j])*q;
c, x[i+j] = Digit(int64(t)>>W2), Digit2(t&M2); // requires arithmetic shift!
}
-
+
// correct if trial digit was too large
if c + Digit(x[k]) != 0 {
// add y
@@ -516,10 +516,10 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) {
// correct trial digit
q--;
}
-
+
x[k] = Digit2(q);
}
-
+
// undo normalization for remainder
if f != 1 {
c := Div1(x[0 : m], x[0 : m], Digit2(f));
@@ -553,9 +553,9 @@ func (x *Natural) Shl(s uint) *Natural {
n := uint(len(x));
m := n + s/W;
z := new(Natural, m+1);
-
+
z[m] = Shl(z[m-n : m], x, s%W);
-
+
return Normalize(z);
}
@@ -567,9 +567,9 @@ func (x *Natural) Shr(s uint) *Natural {
if m == 0 {
m = 0;
}
z := new(Natural, m);
-
+
Shr(z, x[n-m : n], s%W);
-
+
return Normalize(z);
}
@@ -629,7 +629,7 @@ func (x *Natural) Cmp(y *Natural) int {
i := n - 1;
for i > 0 && x[i] == y[i] { i--; }
-
+
d := 0;
switch {
case x[i] < y[i]: d = -1;
@@ -679,7 +679,7 @@ func (x *Natural) String(base uint) string {
if len(x) == 0 {
return "0";
}
-
+
// allocate buffer for conversion
assert(2 <= base && base <= 16);
n := (x.Log2() + 1) / Log2(Digit(base)) + 1; // +1: round up
@@ -688,7 +688,7 @@ func (x *Natural) String(base uint) string {
// don't destroy x
t := new(Natural, len(x));
Or1(t, x, 0); // copy
-
+
// convert
i := n;
for !t.IsZero() {
@@ -730,7 +730,8 @@ func MulAdd1(x *Natural, d, c Digit) *Natural {
// Determines base (octal, decimal, hexadecimal) if base == 0.
-export func NatFromString(s string, base uint, slen *int) *Natural {
+// Returns the number and base.
+export func NatFromString(s string, base uint, slen *int) (*Natural, uint) {
// determine base if necessary
i, n := 0, len(s);
if base == 0 {
@@ -743,7 +744,7 @@ export func NatFromString(s string, base uint, slen *int) *Natural {
}
}
}
-
+
// convert string
assert(2 <= base && base <= 16);\n \tx := Nat(0);\n@@ -761,7 +762,7 @@ export func NatFromString(s string, base uint, slen *int) *Natural {
*slen = i;
}
- return x;\n+ return x, base;\n }\n
@@ -1104,7 +1105,8 @@ func (x *Integer) String(base uint) string {
// Determines base (octal, decimal, hexadecimal) if base == 0.
-export func IntFromString(s string, base uint, slen *int) *Integer {
+// Returns the number and base.
+export func IntFromString(s string, base uint, slen *int) (*Integer, uint) {
// get sign, if any
sign := false;
if len(s) > 0 && (s[0] == '-' || s[0] == '+') {
@@ -1112,14 +1114,15 @@ export func IntFromString(s string, base uint, slen *int) *Integer {
s = s[1 : len(s)];
}
- z := MakeInt(sign, NatFromString(s, base, slen));
+ var mant *Natural;
+ mant, base = NatFromString(s, base, slen);
// correct slen if necessary
if slen != nil && sign {
*slen++;
}
- return z;
+ return MakeInt(sign, mant), base;
}
@@ -1222,24 +1225,33 @@ func (x *Rational) String(base uint) string {
// Determines base (octal, decimal, hexadecimal) if base == 0.
-export func RatFromString(s string, base uint, slen *int) *Rational {
+// Returns the number and base of the nominator.
+export func RatFromString(s string, base uint, slen *int) (*Rational, uint) {
// read nominator
var alen, blen int;
- a := IntFromString(s, base, &alen);
+ a, abase := IntFromString(s, base, &alen);
b := Nat(1);
-
- // read denominator, if any
- if alen < len(s) && s[alen] == '/' {
- alen++;
- if alen < len(s) {
- b = NatFromString(s[alen : len(s)], base, &blen);
+
+ // read denominator or fraction, if any
+ if alen < len(s) {
+ ch := s[alen];
+ if ch == '/' {
+ alen++;
+ b, base = NatFromString(s[alen : len(s)], base, &blen);
+ } else if ch == '.' {
+ alen++;
+ b, base = NatFromString(s[alen : len(s)], abase, &blen);
+ assert(base == abase);
+ f := Nat(base).Pow(uint(blen));
+ a = MakeInt(a.sign, a.mant.Mul(f).Add(b));
+ b = f;
}
}
-
+
// provide number of string bytes consumed if necessary
if slen != nil {
*slen = alen + blen;
}
- return MakeRat(a, b);
+ return MakeRat(a, b), abase;
}
usr/gri/bignum/bignum_test.go
--- a/usr/gri/bignum/bignum_test.go
+++ b/usr/gri/bignum/bignum_test.go
@@ -16,22 +16,40 @@ const (
)
+func NatFromString(s string, base uint, slen *int) *Big.Natural {
+ x, dummy := Big.NatFromString(s, base, slen);
+ return x;
+}
+
+
+func IntFromString(s string, base uint, slen *int) *Big.Integer {
+ x, dummy := Big.IntFromString(s, base, slen);
+ return x;
+}
+
+
+func RatFromString(s string, base uint, slen *int) *Big.Rational {
+ x, dummy := Big.RatFromString(s, base, slen);
+ return x;
+}
+
+
var (
nat_zero = Big.Nat(0);
nat_one = Big.Nat(1);
nat_two = Big.Nat(2);
-
- a = Big.NatFromString(sa, 10, nil);
- b = Big.NatFromString(sb, 10, nil);
- c = Big.NatFromString(sc, 10, nil);
- p = Big.NatFromString(sp, 10, nil);
+
+ a = NatFromString(sa, 10, nil);
+ b = NatFromString(sb, 10, nil);
+ c = NatFromString(sc, 10, nil);
+ p = NatFromString(sp, 10, nil);
int_zero = Big.Int(0);
int_one = Big.Int(1);
int_two = Big.Int(2);
-
- ip = Big.IntFromString(sp, 10, nil);
-
+
+ ip = IntFromString(sp, 10, nil);
+
rat_zero = Big.Rat(0, 1);
rat_half = Big.Rat(1, 2);
rat_one = Big.Rat(1, 1);
@@ -89,17 +107,17 @@ func NatConv() {
test_msg = "NatConvB";
var slen int;
- NAT_EQ(0, Big.NatFromString("0", 0, nil), nat_zero);
- NAT_EQ(1, Big.NatFromString("123", 0, nil), Big.Nat(123));
- NAT_EQ(2, Big.NatFromString("077", 0, nil), Big.Nat(7*8 + 7));
- NAT_EQ(3, Big.NatFromString("0x1f", 0, nil), Big.Nat(1*16 + 15));
- NAT_EQ(4, Big.NatFromString("0x1fg", 0, &slen), Big.Nat(1*16 + 15));
+ NAT_EQ(0, NatFromString("0", 0, nil), nat_zero);
+ NAT_EQ(1, NatFromString("123", 0, nil), Big.Nat(123));
+ NAT_EQ(2, NatFromString("077", 0, nil), Big.Nat(7*8 + 7));
+ NAT_EQ(3, NatFromString("0x1f", 0, nil), Big.Nat(1*16 + 15));
+ NAT_EQ(4, NatFromString("0x1fg", 0, &slen), Big.Nat(1*16 + 15));
TEST(4, slen == 4);
-
+
test_msg = "NatConvC";
t := c.Mul(c);
for base := uint(2); base <= 16; base++ {
- NAT_EQ(base, Big.NatFromString(t.String(base), base, nil), t);
+ NAT_EQ(base, NatFromString(t.String(base), base, nil), t);
}
}
@@ -107,16 +125,16 @@ func NatConv() {
func IntConv() {
test_msg = "IntConv";
var slen int;
- INT_EQ(0, Big.IntFromString("0", 0, nil), int_zero);
- INT_EQ(1, Big.IntFromString("-0", 0, nil), int_zero);
- INT_EQ(2, Big.IntFromString("123", 0, nil), Big.Int(123));
- INT_EQ(3, Big.IntFromString("-123", 0, nil), Big.Int(-123));
- INT_EQ(4, Big.IntFromString("077", 0, nil), Big.Int(7*8 + 7));
- INT_EQ(5, Big.IntFromString("-077", 0, nil), Big.Int(-(7*8 + 7)));
- INT_EQ(6, Big.IntFromString("0x1f", 0, nil), Big.Int(1*16 + 15));
- INT_EQ(7, Big.IntFromString("-0x1f", 0, nil), Big.Int(-(1*16 + 15)));
- INT_EQ(8, Big.IntFromString("0x1fg", 0, &slen), Big.Int(1*16 + 15));
- INT_EQ(9, Big.IntFromString("-0x1fg", 0, &slen), Big.Int(-(1*16 + 15)));
+ INT_EQ(0, IntFromString("0", 0, nil), int_zero);
+ INT_EQ(1, IntFromString("-0", 0, nil), int_zero);
+ INT_EQ(2, IntFromString("123", 0, nil), Big.Int(123));
+ INT_EQ(3, IntFromString("-123", 0, nil), Big.Int(-123));
+ INT_EQ(4, IntFromString("077", 0, nil), Big.Int(7*8 + 7));
+ INT_EQ(5, IntFromString("-077", 0, nil), Big.Int(-(7*8 + 7)));
+ INT_EQ(6, IntFromString("0x1f", 0, nil), Big.Int(1*16 + 15));
+ INT_EQ(7, IntFromString("-0x1f", 0, nil), Big.Int(-(1*16 + 15)));
+ INT_EQ(8, IntFromString("0x1fg", 0, &slen), Big.Int(1*16 + 15));
+ INT_EQ(9, IntFromString("-0x1fg", 0, &slen), Big.Int(-(1*16 + 15)));
TEST(10, slen == 5);
}
@@ -124,12 +142,16 @@ func IntConv() {
func RatConv() {
test_msg = "RatConv";
var slen int;
- RAT_EQ(0, Big.RatFromString("0", 0, nil), rat_zero);
- RAT_EQ(1, Big.RatFromString("0/", 0, nil), rat_zero);
- RAT_EQ(2, Big.RatFromString("0/1", 0, nil), rat_zero);
- RAT_EQ(3, Big.RatFromString("010/8", 0, nil), rat_one);
- RAT_EQ(4, Big.RatFromString("20/0xa", 0, &slen), rat_two);
- TEST(5, slen == 6);
+ RAT_EQ(0, RatFromString("0", 0, nil), rat_zero);
+ RAT_EQ(1, RatFromString("0/1", 0, nil), rat_zero);
+ RAT_EQ(2, RatFromString("0/01", 0, nil), rat_zero);
+ RAT_EQ(3, RatFromString("0x14/10", 0, &slen), rat_two);
+ TEST(4, slen == 7);
+ RAT_EQ(5, RatFromString("0.", 0, nil), rat_zero);
+ RAT_EQ(6, RatFromString("0.001f", 10, nil), Big.Rat(1, 1000));
+ RAT_EQ(7, RatFromString("10101.0101", 2, nil), Big.Rat(0x155, 1<<4));
+ RAT_EQ(8, RatFromString("-0003.145926", 10, &slen), Big.Rat(-3145926, 1000000));
+ TEST(9, slen == 12);
}
@@ -213,11 +235,11 @@ func NatMul() {
test_msg = "NatMulA";
NAT_EQ(0, Mul(c, nat_zero), nat_zero);
NAT_EQ(1, Mul(c, nat_one), c);
-
+
test_msg = "NatMulB";
NAT_EQ(0, b.Mul(Big.MulRange(0, 100)), nat_zero);
NAT_EQ(1, b.Mul(Big.MulRange(21, 100)), c);
-
+
test_msg = "NatMulC";
const n = 100;
p := b.Mul(c).Shl(n);
@@ -234,7 +256,7 @@ func NatDiv() {
NAT_EQ(2, b.Div(c), nat_zero);
NAT_EQ(4, nat_one.Shl(100).Div(nat_one.Shl(90)), nat_one.Shl(10));
NAT_EQ(5, c.Div(b), Big.MulRange(21, 100));
-
+
test_msg = "NatDivB";
const n = 100;
p := Big.Fact(n);
@@ -315,7 +337,7 @@ func NatShift() {
test_msg = "NatShift1L";
TEST(0, b.Shl(0).Cmp(b) == 0);
TEST(1, c.Shl(1).Cmp(c) > 0);
-
+
test_msg = "NatShift1R";
TEST(0, b.Shr(0).Cmp(b) == 0);
TEST(1, c.Shr(1).Cmp(c) < 0);
@@ -349,7 +371,7 @@ func IntShift() {
test_msg = "IntShift1L";
TEST(0, ip.Shl(0).Cmp(ip) == 0);
TEST(1, ip.Shl(1).Cmp(ip) > 0);
-
+
test_msg = "IntShift1R";
TEST(0, ip.Shr(0).Cmp(ip) == 0);
TEST(1, ip.Shr(1).Cmp(ip) < 0);
@@ -376,7 +398,7 @@ func IntShift() {
p = p.Shr(1);
}
}
-
+
test_msg = "IntShift4R";
//INT_EQ(0, Big.Int(-43).Shr(1), Big.Int(-43 >> 1));
//INT_EQ(1, ip.Neg().Shr(10), ip.Neg().Div(Big.Int(1).Shl(10)));
@@ -456,17 +478,17 @@ func main() {
NatGcd();
NatPow();
NatPop();
-
+
// Integers
// TODO add more tests
IntConv();
IntQuoRem();
IntDivMod();
IntShift();
-
+
// Rationals
// TODO add more tests
RatConv();
-
+
print("PASSED\\n");
}
コアとなるコードの解説
usr/gri/bignum/bignum.go
-
NatFromString
,IntFromString
,RatFromString
関数のシグネチャ変更: これらの関数は、文字列から自然数、整数、有理数をパースする役割を担っています。変更前はパースされた数値オブジェクトのみを返していましたが、変更後は(*Type, uint)
のように、パースに実際に使用された基数も返すようになりました。これにより、呼び出し元は基数自動判別(base=0
の場合)の結果を正確に知ることができます。 -
RatFromString
における小数点形式のパースロジックの追加: この関数は、有理数を文字列から構築します。} else if ch == '.' { alen++; b, base = NatFromString(s[alen : len(s)], abase, &blen); assert(base == abase); f := Nat(base).Pow(uint(blen)); a = MakeInt(a.sign, a.mant.Mul(f).Add(b)); b = f; }
このブロックが、小数点形式の文字列(例:
"3.14"
)を処理する新しいロジックです。ch == '.'
で小数点があるかをチェックします。- 小数部の文字列(例:
"14"
)をNatFromString
でパースし、b
に格納します。この際、整数部と同じ基数abase
を使用します。 f := Nat(base).Pow(uint(blen));
で、基数base
を小数部の桁数blen
乗した値(例: 10進数で小数部が2桁なら10^2=100
)を計算します。これが分母の候補となります。a = MakeInt(a.sign, a.mant.Mul(f).Add(b));
で、整数部a
をf
倍し、それに小数部b
を加算することで、分子を計算します。例えば、3.14
の場合、3 * 100 + 14 = 314
となります。b = f;
で、分母をf
に設定します。 これにより、3.14
は314/100
という有理数として表現されます。
-
末尾のタブの削除: コード全体にわたって、行末の不要なタブ文字が削除されています。これは機能的な変更ではなく、コードスタイルと整形に関する改善です。例えば、
Mul11
関数のreturn z1, z0;
の行の後にあったタブが削除されています。
usr/gri/bignum/bignum_test.go
-
ラッパー関数の導入:
func NatFromString(s string, base uint, slen *int) *Big.Natural { x, dummy := Big.NatFromString(s, base, slen); return x; } // IntFromString, RatFromString も同様
bignum.go
で変更されたFromString
関数のシグネチャに対応するため、テストファイル内でこれらのラッパー関数が定義されました。これらのラッパーは、新しいFromString
関数を呼び出し、追加された戻り値(基数)をdummy
変数に格納して破棄することで、既存のテストコードが変更なしで動作するようにしています。 -
RatConv
テストの拡張:--- a/usr/gri/bignum/bignum_test.go +++ b/usr/gri/bignum/bignum_test.go @@ -142,6 +142,10 @@ func RatConv() { TEST(4, slen == 7); RAT_EQ(5, RatFromString("0.", 0, nil), rat_zero); RAT_EQ(6, RatFromString("0.001f", 10, nil), Big.Rat(1, 1000)); + RAT_EQ(7, RatFromString("10101.0101", 2, nil), Big.Rat(0x155, 1<<4)); + RAT_EQ(8, RatFromString("-0003.145926", 10, &slen), Big.Rat(-3145926, 1000000)); + TEST(9, slen == 12); }
このセクションでは、
RatFromString
の新しい小数点形式パース機能が正しく動作するかを検証するテストケースが追加されています。RAT_EQ(5, RatFromString("0.", 0, nil), rat_zero);
:小数点のみの入力のテスト。RAT_EQ(6, RatFromString("0.001f", 10, nil), Big.Rat(1, 1000));
:10進数の小数点のテスト。RAT_EQ(7, RatFromString("10101.0101", 2, nil), Big.Rat(0x155, 1<<4));
:2進数の小数点のテスト。0x155
は10進数の341、1<<4
は10進数の16。10101.0101_2 = 1*16 + 0*8 + 1*4 + 0*2 + 1*1 + 0*1/2 + 1*1/4 + 0*1/8 + 1*1/16 = 21 + 5/16 = 341/16
。RAT_EQ(8, RatFromString("-0003.145926", 10, &slen), Big.Rat(-3145926, 1000000));
:負の数と小数点の組み合わせのテスト。
関連リンク
- Go言語の
math/big
パッケージ(現在の任意精度演算ライブラリ): https://pkg.go.dev/math/big
参考にした情報源リンク
- Git diff の出力
- Go言語の初期開発に関する一般的な知識
- 任意精度演算、基数変換、有理数に関する数学的・計算機科学的知識