Browse Source

cleanup Rounder docs; make most tests blackbox

speter 11 years ago
parent
commit
f312248f41
4 changed files with 246 additions and 266 deletions
  1. 40 0
      dec_internal_test.go
  2. 63 95
      dec_test.go
  3. 67 97
      rounder.go
  4. 76 74
      rounder_test.go

+ 40 - 0
dec_internal_test.go

@@ -0,0 +1,40 @@
+package inf
+
+import (
+	"math/big"
+	"testing"
+)
+
+var decQuoRemZZZ = []struct {
+	z, x, y  *Dec
+	r        *big.Rat
+	srA, srB int
+}{
+	// basic examples
+	{NewDec(1, 0), NewDec(2, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1},
+	{NewDec(15, 1), NewDec(3, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1},
+	{NewDec(1, 1), NewDec(1, 0), NewDec(10, 0), big.NewRat(0, 1), 0, 1},
+	{NewDec(0, 0), NewDec(2, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1},
+	{NewDec(0, 0), NewDec(2, 0), NewDec(6, 0), big.NewRat(1, 3), 1, 1},
+	{NewDec(1, 1), NewDec(2, 0), NewDec(12, 0), big.NewRat(2, 3), 1, 1},
+
+	// examples from the Go Language Specification
+	{NewDec(1, 0), NewDec(5, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1},
+	{NewDec(-1, 0), NewDec(-5, 0), NewDec(3, 0), big.NewRat(-2, 3), -1, 1},
+	{NewDec(-1, 0), NewDec(5, 0), NewDec(-3, 0), big.NewRat(-2, 3), 1, -1},
+	{NewDec(1, 0), NewDec(-5, 0), NewDec(-3, 0), big.NewRat(2, 3), -1, -1},
+}
+
+func TestDecQuoRem(t *testing.T) {
+	for i, a := range decQuoRemZZZ {
+		z, rA, rB := new(Dec), new(big.Int), new(big.Int)
+		s := scaleQuoExact{}.Scale(a.x, a.y)
+		z.quoRem(a.x, a.y, s, true, rA, rB)
+		if a.z.Cmp(z) != 0 || a.r.Cmp(new(big.Rat).SetFrac(rA, rB)) != 0 {
+			t.Errorf("#%d QuoRemZZZ got %v, %v, %v; expected %v, %v", i, z, rA, rB, a.z, a.r)
+		}
+		if a.srA != rA.Sign() || a.srB != rB.Sign() {
+			t.Errorf("#%d QuoRemZZZ wrong signs, got %v, %v; expected %v, %v", i, rA.Sign(), rB.Sign(), a.srA, a.srB)
+		}
+	}
+}

+ 63 - 95
dec_test.go

@@ -1,4 +1,4 @@
-package inf
+package inf_test
 
 
 import (
 import (
 	"bytes"
 	"bytes"
@@ -7,35 +7,37 @@ import (
 	"math/big"
 	"math/big"
 	"strings"
 	"strings"
 	"testing"
 	"testing"
+
+	"speter.net/go/exp/math/dec/inf"
 )
 )
 
 
-type decFunZZ func(z, x, y *Dec) *Dec
+type decFunZZ func(z, x, y *inf.Dec) *inf.Dec
 type decArgZZ struct {
 type decArgZZ struct {
-	z, x, y *Dec
+	z, x, y *inf.Dec
 }
 }
 
 
 var decSumZZ = []decArgZZ{
 var decSumZZ = []decArgZZ{
-	{NewDec(0, 0), NewDec(0, 0), NewDec(0, 0)},
-	{NewDec(1, 0), NewDec(1, 0), NewDec(0, 0)},
-	{NewDec(1111111110, 0), NewDec(123456789, 0), NewDec(987654321, 0)},
-	{NewDec(-1, 0), NewDec(-1, 0), NewDec(0, 0)},
-	{NewDec(864197532, 0), NewDec(-123456789, 0), NewDec(987654321, 0)},
-	{NewDec(-1111111110, 0), NewDec(-123456789, 0), NewDec(-987654321, 0)},
-	{NewDec(12, 2), NewDec(1, 1), NewDec(2, 2)},
+	{inf.NewDec(0, 0), inf.NewDec(0, 0), inf.NewDec(0, 0)},
+	{inf.NewDec(1, 0), inf.NewDec(1, 0), inf.NewDec(0, 0)},
+	{inf.NewDec(1111111110, 0), inf.NewDec(123456789, 0), inf.NewDec(987654321, 0)},
+	{inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(0, 0)},
+	{inf.NewDec(864197532, 0), inf.NewDec(-123456789, 0), inf.NewDec(987654321, 0)},
+	{inf.NewDec(-1111111110, 0), inf.NewDec(-123456789, 0), inf.NewDec(-987654321, 0)},
+	{inf.NewDec(12, 2), inf.NewDec(1, 1), inf.NewDec(2, 2)},
 }
 }
 
 
 var decProdZZ = []decArgZZ{
 var decProdZZ = []decArgZZ{
-	{NewDec(0, 0), NewDec(0, 0), NewDec(0, 0)},
-	{NewDec(0, 0), NewDec(1, 0), NewDec(0, 0)},
-	{NewDec(1, 0), NewDec(1, 0), NewDec(1, 0)},
-	{NewDec(-991*991, 0), NewDec(991, 0), NewDec(-991, 0)},
-	{NewDec(2, 3), NewDec(1, 1), NewDec(2, 2)},
-	{NewDec(2, -3), NewDec(1, -1), NewDec(2, -2)},
-	{NewDec(2, 3), NewDec(1, 1), NewDec(2, 2)},
+	{inf.NewDec(0, 0), inf.NewDec(0, 0), inf.NewDec(0, 0)},
+	{inf.NewDec(0, 0), inf.NewDec(1, 0), inf.NewDec(0, 0)},
+	{inf.NewDec(1, 0), inf.NewDec(1, 0), inf.NewDec(1, 0)},
+	{inf.NewDec(-991*991, 0), inf.NewDec(991, 0), inf.NewDec(-991, 0)},
+	{inf.NewDec(2, 3), inf.NewDec(1, 1), inf.NewDec(2, 2)},
+	{inf.NewDec(2, -3), inf.NewDec(1, -1), inf.NewDec(2, -2)},
+	{inf.NewDec(2, 3), inf.NewDec(1, 1), inf.NewDec(2, 2)},
 }
 }
 
 
 func TestDecSignZ(t *testing.T) {
 func TestDecSignZ(t *testing.T) {
-	var zero Dec
+	var zero inf.Dec
 	for _, a := range decSumZZ {
 	for _, a := range decSumZZ {
 		s := a.z.Sign()
 		s := a.z.Sign()
 		e := a.z.Cmp(&zero)
 		e := a.z.Cmp(&zero)
@@ -46,11 +48,11 @@ func TestDecSignZ(t *testing.T) {
 }
 }
 
 
 func TestDecAbsZ(t *testing.T) {
 func TestDecAbsZ(t *testing.T) {
-	var zero Dec
+	var zero inf.Dec
 	for _, a := range decSumZZ {
 	for _, a := range decSumZZ {
-		var z Dec
+		var z inf.Dec
 		z.Abs(a.z)
 		z.Abs(a.z)
-		var e Dec
+		var e inf.Dec
 		e.Set(a.z)
 		e.Set(a.z)
 		if e.Cmp(&zero) < 0 {
 		if e.Cmp(&zero) < 0 {
 			e.Sub(&zero, &e)
 			e.Sub(&zero, &e)
@@ -62,7 +64,7 @@ func TestDecAbsZ(t *testing.T) {
 }
 }
 
 
 func testDecFunZZ(t *testing.T, msg string, f decFunZZ, a decArgZZ) {
 func testDecFunZZ(t *testing.T, msg string, f decFunZZ, a decArgZZ) {
-	var z Dec
+	var z inf.Dec
 	f(&z, a.x, a.y)
 	f(&z, a.x, a.y)
 	if (&z).Cmp(a.z) != 0 {
 	if (&z).Cmp(a.z) != 0 {
 		t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
 		t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
@@ -70,8 +72,8 @@ func testDecFunZZ(t *testing.T, msg string, f decFunZZ, a decArgZZ) {
 }
 }
 
 
 func TestDecSumZZ(t *testing.T) {
 func TestDecSumZZ(t *testing.T) {
-	AddZZ := func(z, x, y *Dec) *Dec { return z.Add(x, y) }
-	SubZZ := func(z, x, y *Dec) *Dec { return z.Sub(x, y) }
+	AddZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Add(x, y) }
+	SubZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Sub(x, y) }
 	for _, a := range decSumZZ {
 	for _, a := range decSumZZ {
 		arg := a
 		arg := a
 		testDecFunZZ(t, "AddZZ", AddZZ, arg)
 		testDecFunZZ(t, "AddZZ", AddZZ, arg)
@@ -88,7 +90,7 @@ func TestDecSumZZ(t *testing.T) {
 }
 }
 
 
 func TestDecProdZZ(t *testing.T) {
 func TestDecProdZZ(t *testing.T) {
-	MulZZ := func(z, x, y *Dec) *Dec { return z.Mul(x, y) }
+	MulZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Mul(x, y) }
 	for _, a := range decProdZZ {
 	for _, a := range decProdZZ {
 		arg := a
 		arg := a
 		testDecFunZZ(t, "MulZZ", MulZZ, arg)
 		testDecFunZZ(t, "MulZZ", MulZZ, arg)
@@ -98,51 +100,17 @@ func TestDecProdZZ(t *testing.T) {
 	}
 	}
 }
 }
 
 
-var decQuoRemZZZ = []struct {
-	z, x, y  *Dec
-	r        *big.Rat
-	srA, srB int
-}{
-	// basic examples
-	{NewDec(1, 0), NewDec(2, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1},
-	{NewDec(15, 1), NewDec(3, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1},
-	{NewDec(1, 1), NewDec(1, 0), NewDec(10, 0), big.NewRat(0, 1), 0, 1},
-	{NewDec(0, 0), NewDec(2, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1},
-	{NewDec(0, 0), NewDec(2, 0), NewDec(6, 0), big.NewRat(1, 3), 1, 1},
-	{NewDec(1, 1), NewDec(2, 0), NewDec(12, 0), big.NewRat(2, 3), 1, 1},
-
-	// examples from the Go Language Specification
-	{NewDec(1, 0), NewDec(5, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1},
-	{NewDec(-1, 0), NewDec(-5, 0), NewDec(3, 0), big.NewRat(-2, 3), -1, 1},
-	{NewDec(-1, 0), NewDec(5, 0), NewDec(-3, 0), big.NewRat(-2, 3), 1, -1},
-	{NewDec(1, 0), NewDec(-5, 0), NewDec(-3, 0), big.NewRat(2, 3), -1, -1},
-}
-
-func TestDecQuoRem(t *testing.T) {
-	for i, a := range decQuoRemZZZ {
-		z, rA, rB := new(Dec), new(big.Int), new(big.Int)
-		s := scaleQuoExact{}.Scale(a.x, a.y)
-		z.quoRem(a.x, a.y, s, true, rA, rB)
-		if a.z.Cmp(z) != 0 || a.r.Cmp(new(big.Rat).SetFrac(rA, rB)) != 0 {
-			t.Errorf("#%d QuoRemZZZ got %v, %v, %v; expected %v, %v", i, z, rA, rB, a.z, a.r)
-		}
-		if a.srA != rA.Sign() || a.srB != rB.Sign() {
-			t.Errorf("#%d QuoRemZZZ wrong signs, got %v, %v; expected %v, %v", i, rA.Sign(), rB.Sign(), a.srA, a.srB)
-		}
-	}
-}
-
 var decUnscaledTests = []struct {
 var decUnscaledTests = []struct {
-	d  *Dec
+	d  *inf.Dec
 	u  int64 // ignored when ok == false
 	u  int64 // ignored when ok == false
 	ok bool
 	ok bool
 }{
 }{
-	{new(Dec), 0, true},
-	{NewDec(-1<<63, 0), -1 << 63, true},
-	{NewDec(-(-1<<63 + 1), 0), -(-1<<63 + 1), true},
-	{new(Dec).Neg(NewDec(-1<<63, 0)), 0, false},
-	{new(Dec).Sub(NewDec(-1<<63, 0), NewDec(1, 0)), 0, false},
-	{NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), 0, false},
+	{new(inf.Dec), 0, true},
+	{inf.NewDec(-1<<63, 0), -1 << 63, true},
+	{inf.NewDec(-(-1<<63 + 1), 0), -(-1<<63 + 1), true},
+	{new(inf.Dec).Neg(inf.NewDec(-1<<63, 0)), 0, false},
+	{new(inf.Dec).Sub(inf.NewDec(-1<<63, 0), inf.NewDec(1, 0)), 0, false},
+	{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), 0, false},
 }
 }
 
 
 func TestDecUnscaled(t *testing.T) {
 func TestDecUnscaled(t *testing.T) {
@@ -157,26 +125,26 @@ func TestDecUnscaled(t *testing.T) {
 }
 }
 
 
 var decRoundTests = [...]struct {
 var decRoundTests = [...]struct {
-	in  *Dec
-	s   Scale
-	r   Rounder
-	exp *Dec
+	in  *inf.Dec
+	s   inf.Scale
+	r   inf.Rounder
+	exp *inf.Dec
 }{
 }{
-	{NewDec(123424999999999993, 15), 2, RoundHalfUp, NewDec(12342, 2)},
-	{NewDec(123425000000000001, 15), 2, RoundHalfUp, NewDec(12343, 2)},
-	{NewDec(123424999999999993, 15), 15, RoundHalfUp, NewDec(123424999999999993, 15)},
-	{NewDec(123424999999999993, 15), 16, RoundHalfUp, NewDec(1234249999999999930, 16)},
-	{NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -1, RoundHalfUp, NewDec(1844674407370955162, -1)},
-	{NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -2, RoundHalfUp, NewDec(184467440737095516, -2)},
-	{NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -3, RoundHalfUp, NewDec(18446744073709552, -3)},
-	{NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -4, RoundHalfUp, NewDec(1844674407370955, -4)},
-	{NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -5, RoundHalfUp, NewDec(184467440737096, -5)},
-	{NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -6, RoundHalfUp, NewDec(18446744073710, -6)},
+	{inf.NewDec(123424999999999993, 15), 2, inf.RoundHalfUp, inf.NewDec(12342, 2)},
+	{inf.NewDec(123425000000000001, 15), 2, inf.RoundHalfUp, inf.NewDec(12343, 2)},
+	{inf.NewDec(123424999999999993, 15), 15, inf.RoundHalfUp, inf.NewDec(123424999999999993, 15)},
+	{inf.NewDec(123424999999999993, 15), 16, inf.RoundHalfUp, inf.NewDec(1234249999999999930, 16)},
+	{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -1, inf.RoundHalfUp, inf.NewDec(1844674407370955162, -1)},
+	{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -2, inf.RoundHalfUp, inf.NewDec(184467440737095516, -2)},
+	{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -3, inf.RoundHalfUp, inf.NewDec(18446744073709552, -3)},
+	{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -4, inf.RoundHalfUp, inf.NewDec(1844674407370955, -4)},
+	{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -5, inf.RoundHalfUp, inf.NewDec(184467440737096, -5)},
+	{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -6, inf.RoundHalfUp, inf.NewDec(18446744073710, -6)},
 }
 }
 
 
 func TestDecRound(t *testing.T) {
 func TestDecRound(t *testing.T) {
 	for i, tt := range decRoundTests {
 	for i, tt := range decRoundTests {
-		z := new(Dec).Round(tt.in, tt.s, tt.r)
+		z := new(inf.Dec).Round(tt.in, tt.s, tt.r)
 		if tt.exp.Cmp(z) != 0 {
 		if tt.exp.Cmp(z) != 0 {
 			t.Errorf("#%d Round got %v; expected %v", i, z, tt.exp)
 			t.Errorf("#%d Round got %v; expected %v", i, z, tt.exp)
 		}
 		}
@@ -187,7 +155,7 @@ var decStringTests = []struct {
 	in     string
 	in     string
 	out    string
 	out    string
 	val    int64
 	val    int64
-	scale  Scale // skip SetString if negative
+	scale  inf.Scale // skip SetString if negative
 	ok     bool
 	ok     bool
 	scanOk bool
 	scanOk bool
 }{
 }{
@@ -240,7 +208,7 @@ var decStringTests = []struct {
 }
 }
 
 
 func TestDecGetString(t *testing.T) {
 func TestDecGetString(t *testing.T) {
-	z := new(Dec)
+	z := new(inf.Dec)
 	for i, test := range decStringTests {
 	for i, test := range decStringTests {
 		if !test.ok {
 		if !test.ok {
 			continue
 			continue
@@ -261,7 +229,7 @@ func TestDecGetString(t *testing.T) {
 }
 }
 
 
 func TestDecSetString(t *testing.T) {
 func TestDecSetString(t *testing.T) {
-	tmp := new(Dec)
+	tmp := new(inf.Dec)
 	for i, test := range decStringTests {
 	for i, test := range decStringTests {
 		if test.scale < 0 {
 		if test.scale < 0 {
 			// SetString only supports scale >= 0
 			// SetString only supports scale >= 0
@@ -269,10 +237,10 @@ func TestDecSetString(t *testing.T) {
 		}
 		}
 		// initialize to a non-zero value so that issues with parsing
 		// initialize to a non-zero value so that issues with parsing
 		// 0 are detected
 		// 0 are detected
-		tmp.Set(NewDec(1234567890, 123))
-		n1, ok1 := new(Dec).SetString(test.in)
+		tmp.Set(inf.NewDec(1234567890, 123))
+		n1, ok1 := new(inf.Dec).SetString(test.in)
 		n2, ok2 := tmp.SetString(test.in)
 		n2, ok2 := tmp.SetString(test.in)
-		expected := NewDec(test.val, test.scale)
+		expected := inf.NewDec(test.val, test.scale)
 		if ok1 != test.ok || ok2 != test.ok {
 		if ok1 != test.ok || ok2 != test.ok {
 			t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
 			t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
 			continue
 			continue
@@ -300,7 +268,7 @@ func TestDecSetString(t *testing.T) {
 }
 }
 
 
 func TestDecScan(t *testing.T) {
 func TestDecScan(t *testing.T) {
-	tmp := new(Dec)
+	tmp := new(inf.Dec)
 	for i, test := range decStringTests {
 	for i, test := range decStringTests {
 		if test.scale < 0 {
 		if test.scale < 0 {
 			// SetString only supports scale >= 0
 			// SetString only supports scale >= 0
@@ -308,8 +276,8 @@ func TestDecScan(t *testing.T) {
 		}
 		}
 		// initialize to a non-zero value so that issues with parsing
 		// initialize to a non-zero value so that issues with parsing
 		// 0 are detected
 		// 0 are detected
-		tmp.Set(NewDec(1234567890, 123))
-		n1, n2 := new(Dec), tmp
+		tmp.Set(inf.NewDec(1234567890, 123))
+		n1, n2 := new(inf.Dec), tmp
 		nn1, err1 := fmt.Sscan(test.in, n1)
 		nn1, err1 := fmt.Sscan(test.in, n1)
 		nn2, err2 := fmt.Sscan(test.in, n2)
 		nn2, err2 := fmt.Sscan(test.in, n2)
 		if !test.scanOk {
 		if !test.scanOk {
@@ -318,7 +286,7 @@ func TestDecScan(t *testing.T) {
 			}
 			}
 			continue
 			continue
 		}
 		}
-		expected := NewDec(test.val, test.scale)
+		expected := inf.NewDec(test.val, test.scale)
 		if nn1 != 1 || err1 != nil || nn2 != 1 || err2 != nil {
 		if nn1 != 1 || err1 != nil || nn2 != 1 || err2 != nil {
 			t.Errorf("#%d (input '%s') error %d %v, %d %v", i, test.in, nn1, err1, nn2, err2)
 			t.Errorf("#%d (input '%s') error %d %v, %d %v", i, test.in, nn1, err1, nn2, err2)
 			continue
 			continue
@@ -355,7 +323,7 @@ var decScanNextTests = []struct {
 func TestDecScanNext(t *testing.T) {
 func TestDecScanNext(t *testing.T) {
 	for i, test := range decScanNextTests {
 	for i, test := range decScanNextTests {
 		rdr := strings.NewReader(test.in)
 		rdr := strings.NewReader(test.in)
-		n1 := new(Dec)
+		n1 := new(inf.Dec)
 		nn1, _ := fmt.Fscan(rdr, n1)
 		nn1, _ := fmt.Fscan(rdr, n1)
 		if (test.ok && nn1 == 0) || (!test.ok && nn1 > 0) {
 		if (test.ok && nn1 == 0) || (!test.ok && nn1 > 0) {
 			t.Errorf("#%d (input '%s') ok incorrect should be %t", i, test.in, test.ok)
 			t.Errorf("#%d (input '%s') ok incorrect should be %t", i, test.in, test.ok)
@@ -385,20 +353,20 @@ func TestDecGobEncoding(t *testing.T) {
 	dec := gob.NewDecoder(&medium)
 	dec := gob.NewDecoder(&medium)
 	for i, test := range decGobEncodingTests {
 	for i, test := range decGobEncodingTests {
 		for j := 0; j < 2; j++ {
 		for j := 0; j < 2; j++ {
-			for k := Scale(-5); k <= 5; k++ {
+			for k := inf.Scale(-5); k <= 5; k++ {
 				medium.Reset() // empty buffer for each test case (in case of failures)
 				medium.Reset() // empty buffer for each test case (in case of failures)
 				stest := test
 				stest := test
 				if j != 0 {
 				if j != 0 {
 					// negative numbers
 					// negative numbers
 					stest = "-" + test
 					stest = "-" + test
 				}
 				}
-				var tx Dec
+				var tx inf.Dec
 				tx.SetString(stest)
 				tx.SetString(stest)
 				tx.SetScale(k) // test with positive, negative, and zero scale
 				tx.SetScale(k) // test with positive, negative, and zero scale
 				if err := enc.Encode(&tx); err != nil {
 				if err := enc.Encode(&tx); err != nil {
 					t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
 					t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
 				}
 				}
-				var rx Dec
+				var rx inf.Dec
 				if err := dec.Decode(&rx); err != nil {
 				if err := dec.Decode(&rx); err != nil {
 					t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
 					t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
 				}
 				}

+ 67 - 97
rounder.go

@@ -12,6 +12,24 @@ import (
 //
 //
 type Rounder rounder
 type Rounder rounder
 
 
+// See http://speleotrove.com/decimal/damodel.html#refround for more detailed
+// definitions of these rounding modes.
+var (
+	RoundDown     Rounder // towards 0
+	RoundUp       Rounder // away from 0
+	RoundFloor    Rounder // towards -infinity
+	RoundCeil     Rounder // towards +infinity
+	RoundHalfDown Rounder // to nearest; towards 0 if same distance
+	RoundHalfUp   Rounder // to nearest; away from 0 if same distance
+	RoundHalfEven Rounder // to nearest; even last digit if same distance
+)
+
+// RoundExact is to be used in the case when rounding is not necessary.
+// When used with Quo or Round, it returns the result verbatim when it can be
+// expressed exactly with the given precision, and it returns nil otherwise.
+// QuoExact is a shorthand for using Quo with RoundExact.
+var RoundExact Rounder
+
 type rounder interface {
 type rounder interface {
 
 
 	// When UseRemainder() returns true, the Round() method is passed the
 	// When UseRemainder() returns true, the Round() method is passed the
@@ -46,73 +64,8 @@ func (r rndr) Round(z, quo *Dec, remNum, remDen *big.Int) *Dec {
 	return r.round(z, quo, remNum, remDen)
 	return r.round(z, quo, remNum, remDen)
 }
 }
 
 
-// RoundExact returns quo if rem is zero, or nil otherwise. It is intended to
-// be used with ScaleQuoExact when it is guaranteed that the result can be
-// obtained without rounding. QuoExact is a shorthand for such a quotient
-// operation.
-//
-var RoundExact Rounder = roundExact
-
-// RoundDown rounds towards 0; that is, returns the Dec with the greatest
-// absolute value not exceeding that of the result represented by quo and rem.
-//
-var RoundDown Rounder = roundDown
-
-// RoundUp rounds away from 0; that is, returns the Dec with the smallest
-// absolute value not smaller than that of the result represented by quo and
-// rem.
-//
-var RoundUp Rounder = roundUp
-
-// RoundHalfDown rounds to the nearest Dec, and when the remainder is 1/2, it
-// rounds to the Dec with the lower absolute value.
-//
-var RoundHalfDown Rounder = roundHalfDown
-
-// RoundHalfUp rounds to the nearest Dec, and when the remainder is 1/2, it
-// rounds to the Dec with the greater absolute value.
-//
-var RoundHalfUp Rounder = roundHalfUp
-
-// RoundHalfEven rounds to the nearest Dec, and when the remainder is 1/2, it
-// rounds to the Dec with even last digit.
-//
-var RoundHalfEven Rounder = roundHalfEven
-
-// RoundFloor rounds towards negative infinity; that is, returns the greatest
-// Dec not exceeding the result represented by quo and rem.
-//
-var RoundFloor Rounder = roundFloor
-
-// RoundCeil rounds towards positive infinity; that is, returns the
-// smallest Dec not smaller than the result represented by quo and rem.
-//
-var RoundCeil Rounder = roundCeil
-
 var intSign = []*big.Int{big.NewInt(-1), big.NewInt(0), big.NewInt(1)}
 var intSign = []*big.Int{big.NewInt(-1), big.NewInt(0), big.NewInt(1)}
 
 
-var roundExact = rndr{true,
-	func(z, q *Dec, rA, rB *big.Int) *Dec {
-		if rA.Sign() != 0 {
-			return nil
-		}
-		return z.Set(q)
-	}}
-
-var roundDown = rndr{false,
-	func(z, q *Dec, rA, rB *big.Int) *Dec {
-		return z.Set(q)
-	}}
-
-var roundUp = rndr{true,
-	func(z, q *Dec, rA, rB *big.Int) *Dec {
-		z.Set(q)
-		if rA.Sign() != 0 {
-			z.UnscaledBig().Add(z.UnscaledBig(), intSign[rA.Sign()*rB.Sign()+1])
-		}
-		return z
-	}}
-
 func roundHalf(f func(c int, odd uint) (roundUp bool)) func(z, q *Dec, rA, rB *big.Int) *Dec {
 func roundHalf(f func(c int, odd uint) (roundUp bool)) func(z, q *Dec, rA, rB *big.Int) *Dec {
 	return func(z, q *Dec, rA, rB *big.Int) *Dec {
 	return func(z, q *Dec, rA, rB *big.Int) *Dec {
 		z.Set(q)
 		z.Set(q)
@@ -141,35 +94,52 @@ func roundHalf(f func(c int, odd uint) (roundUp bool)) func(z, q *Dec, rA, rB *b
 	}
 	}
 }
 }
 
 
-var roundHalfDown = rndr{true, roundHalf(
-	func(c int, odd uint) bool {
-		return c > 0
-	})}
-
-var roundHalfUp = rndr{true, roundHalf(
-	func(c int, odd uint) bool {
-		return c >= 0
-	})}
-
-var roundHalfEven = rndr{true, roundHalf(
-	func(c int, odd uint) bool {
-		return c > 0 || c == 0 && odd == 1
-	})}
-
-var roundFloor = rndr{true,
-	func(z, q *Dec, rA, rB *big.Int) *Dec {
-		z.Set(q)
-		if rA.Sign()*rB.Sign() < 0 {
-			z.UnscaledBig().Add(z.UnscaledBig(), intSign[0])
-		}
-		return z
-	}}
-
-var roundCeil = rndr{true,
-	func(z, q *Dec, rA, rB *big.Int) *Dec {
-		z.Set(q)
-		if rA.Sign()*rB.Sign() > 0 {
-			z.UnscaledBig().Add(z.UnscaledBig(), intSign[2])
-		}
-		return z
-	}}
+func init() {
+	RoundExact = rndr{true,
+		func(z, q *Dec, rA, rB *big.Int) *Dec {
+			if rA.Sign() != 0 {
+				return nil
+			}
+			return z.Set(q)
+		}}
+	RoundDown = rndr{false,
+		func(z, q *Dec, rA, rB *big.Int) *Dec {
+			return z.Set(q)
+		}}
+	RoundUp = rndr{true,
+		func(z, q *Dec, rA, rB *big.Int) *Dec {
+			z.Set(q)
+			if rA.Sign() != 0 {
+				z.UnscaledBig().Add(z.UnscaledBig(), intSign[rA.Sign()*rB.Sign()+1])
+			}
+			return z
+		}}
+	RoundFloor = rndr{true,
+		func(z, q *Dec, rA, rB *big.Int) *Dec {
+			z.Set(q)
+			if rA.Sign()*rB.Sign() < 0 {
+				z.UnscaledBig().Add(z.UnscaledBig(), intSign[0])
+			}
+			return z
+		}}
+	RoundCeil = rndr{true,
+		func(z, q *Dec, rA, rB *big.Int) *Dec {
+			z.Set(q)
+			if rA.Sign()*rB.Sign() > 0 {
+				z.UnscaledBig().Add(z.UnscaledBig(), intSign[2])
+			}
+			return z
+		}}
+	RoundHalfDown = rndr{true, roundHalf(
+		func(c int, odd uint) bool {
+			return c > 0
+		})}
+	RoundHalfUp = rndr{true, roundHalf(
+		func(c int, odd uint) bool {
+			return c >= 0
+		})}
+	RoundHalfEven = rndr{true, roundHalf(
+		func(c int, odd uint) bool {
+			return c > 0 || c == 0 && odd == 1
+		})}
+}

+ 76 - 74
rounder_test.go

@@ -1,99 +1,101 @@
-package inf
+package inf_test
 
 
 import (
 import (
 	"math/big"
 	"math/big"
 	"testing"
 	"testing"
+
+	"speter.net/go/exp/math/dec/inf"
 )
 )
 
 
 var decRounderInputs = [...]struct {
 var decRounderInputs = [...]struct {
-	quo    *Dec
+	quo    *inf.Dec
 	rA, rB *big.Int
 	rA, rB *big.Int
 }{
 }{
 	// examples from go language spec
 	// examples from go language spec
-	{NewDec(1, 0), big.NewInt(2), big.NewInt(3)},   //  5 /  3
-	{NewDec(-1, 0), big.NewInt(-2), big.NewInt(3)}, // -5 /  3
-	{NewDec(-1, 0), big.NewInt(2), big.NewInt(-3)}, //  5 / -3
-	{NewDec(1, 0), big.NewInt(-2), big.NewInt(-3)}, // -5 / -3
+	{inf.NewDec(1, 0), big.NewInt(2), big.NewInt(3)},   //  5 /  3
+	{inf.NewDec(-1, 0), big.NewInt(-2), big.NewInt(3)}, // -5 /  3
+	{inf.NewDec(-1, 0), big.NewInt(2), big.NewInt(-3)}, //  5 / -3
+	{inf.NewDec(1, 0), big.NewInt(-2), big.NewInt(-3)}, // -5 / -3
 	// examples from godoc
 	// examples from godoc
-	{NewDec(-1, 1), big.NewInt(-8), big.NewInt(10)},
-	{NewDec(-1, 1), big.NewInt(-5), big.NewInt(10)},
-	{NewDec(-1, 1), big.NewInt(-2), big.NewInt(10)},
-	{NewDec(0, 1), big.NewInt(-8), big.NewInt(10)},
-	{NewDec(0, 1), big.NewInt(-5), big.NewInt(10)},
-	{NewDec(0, 1), big.NewInt(-2), big.NewInt(10)},
-	{NewDec(0, 1), big.NewInt(0), big.NewInt(1)},
-	{NewDec(0, 1), big.NewInt(2), big.NewInt(10)},
-	{NewDec(0, 1), big.NewInt(5), big.NewInt(10)},
-	{NewDec(0, 1), big.NewInt(8), big.NewInt(10)},
-	{NewDec(1, 1), big.NewInt(2), big.NewInt(10)},
-	{NewDec(1, 1), big.NewInt(5), big.NewInt(10)},
-	{NewDec(1, 1), big.NewInt(8), big.NewInt(10)},
+	{inf.NewDec(-1, 1), big.NewInt(-8), big.NewInt(10)},
+	{inf.NewDec(-1, 1), big.NewInt(-5), big.NewInt(10)},
+	{inf.NewDec(-1, 1), big.NewInt(-2), big.NewInt(10)},
+	{inf.NewDec(0, 1), big.NewInt(-8), big.NewInt(10)},
+	{inf.NewDec(0, 1), big.NewInt(-5), big.NewInt(10)},
+	{inf.NewDec(0, 1), big.NewInt(-2), big.NewInt(10)},
+	{inf.NewDec(0, 1), big.NewInt(0), big.NewInt(1)},
+	{inf.NewDec(0, 1), big.NewInt(2), big.NewInt(10)},
+	{inf.NewDec(0, 1), big.NewInt(5), big.NewInt(10)},
+	{inf.NewDec(0, 1), big.NewInt(8), big.NewInt(10)},
+	{inf.NewDec(1, 1), big.NewInt(2), big.NewInt(10)},
+	{inf.NewDec(1, 1), big.NewInt(5), big.NewInt(10)},
+	{inf.NewDec(1, 1), big.NewInt(8), big.NewInt(10)},
 }
 }
 
 
 var decRounderResults = [...]struct {
 var decRounderResults = [...]struct {
-	rounder Rounder
-	results [len(decRounderInputs)]*Dec
+	rounder inf.Rounder
+	results [len(decRounderInputs)]*inf.Dec
 }{
 }{
-	{RoundExact, [...]*Dec{nil, nil, nil, nil,
+	{inf.RoundExact, [...]*inf.Dec{nil, nil, nil, nil,
 		nil, nil, nil, nil, nil, nil,
 		nil, nil, nil, nil, nil, nil,
-		NewDec(0, 1), nil, nil, nil, nil, nil, nil}},
-	{RoundDown, [...]*Dec{
-		NewDec(1, 0), NewDec(-1, 0), NewDec(-1, 0), NewDec(1, 0),
-		NewDec(-1, 1), NewDec(-1, 1), NewDec(-1, 1),
-		NewDec(0, 1), NewDec(0, 1), NewDec(0, 1),
-		NewDec(0, 1),
-		NewDec(0, 1), NewDec(0, 1), NewDec(0, 1),
-		NewDec(1, 1), NewDec(1, 1), NewDec(1, 1)}},
-	{RoundUp, [...]*Dec{
-		NewDec(2, 0), NewDec(-2, 0), NewDec(-2, 0), NewDec(2, 0),
-		NewDec(-2, 1), NewDec(-2, 1), NewDec(-2, 1),
-		NewDec(-1, 1), NewDec(-1, 1), NewDec(-1, 1),
-		NewDec(0, 1),
-		NewDec(1, 1), NewDec(1, 1), NewDec(1, 1),
-		NewDec(2, 1), NewDec(2, 1), NewDec(2, 1)}},
-	{RoundHalfDown, [...]*Dec{
-		NewDec(2, 0), NewDec(-2, 0), NewDec(-2, 0), NewDec(2, 0),
-		NewDec(-2, 1), NewDec(-1, 1), NewDec(-1, 1),
-		NewDec(-1, 1), NewDec(0, 1), NewDec(0, 1),
-		NewDec(0, 1),
-		NewDec(0, 1), NewDec(0, 1), NewDec(1, 1),
-		NewDec(1, 1), NewDec(1, 1), NewDec(2, 1)}},
-	{RoundHalfUp, [...]*Dec{
-		NewDec(2, 0), NewDec(-2, 0), NewDec(-2, 0), NewDec(2, 0),
-		NewDec(-2, 1), NewDec(-2, 1), NewDec(-1, 1),
-		NewDec(-1, 1), NewDec(-1, 1), NewDec(0, 1),
-		NewDec(0, 1),
-		NewDec(0, 1), NewDec(1, 1), NewDec(1, 1),
-		NewDec(1, 1), NewDec(2, 1), NewDec(2, 1)}},
-	{RoundHalfEven, [...]*Dec{
-		NewDec(2, 0), NewDec(-2, 0), NewDec(-2, 0), NewDec(2, 0),
-		NewDec(-2, 1), NewDec(-2, 1), NewDec(-1, 1),
-		NewDec(-1, 1), NewDec(0, 1), NewDec(0, 1),
-		NewDec(0, 1),
-		NewDec(0, 1), NewDec(0, 1), NewDec(1, 1),
-		NewDec(1, 1), NewDec(2, 1), NewDec(2, 1)}},
-	{RoundFloor, [...]*Dec{
-		NewDec(1, 0), NewDec(-2, 0), NewDec(-2, 0), NewDec(1, 0),
-		NewDec(-2, 1), NewDec(-2, 1), NewDec(-2, 1),
-		NewDec(-1, 1), NewDec(-1, 1), NewDec(-1, 1),
-		NewDec(0, 1),
-		NewDec(0, 1), NewDec(0, 1), NewDec(0, 1),
-		NewDec(1, 1), NewDec(1, 1), NewDec(1, 1)}},
-	{RoundCeil, [...]*Dec{
-		NewDec(2, 0), NewDec(-1, 0), NewDec(-1, 0), NewDec(2, 0),
-		NewDec(-1, 1), NewDec(-1, 1), NewDec(-1, 1),
-		NewDec(0, 1), NewDec(0, 1), NewDec(0, 1),
-		NewDec(0, 1),
-		NewDec(1, 1), NewDec(1, 1), NewDec(1, 1),
-		NewDec(2, 1), NewDec(2, 1), NewDec(2, 1)}},
+		inf.NewDec(0, 1), nil, nil, nil, nil, nil, nil}},
+	{inf.RoundDown, [...]*inf.Dec{
+		inf.NewDec(1, 0), inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(1, 0),
+		inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
+		inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
+		inf.NewDec(0, 1),
+		inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
+		inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1)}},
+	{inf.RoundUp, [...]*inf.Dec{
+		inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0),
+		inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-2, 1),
+		inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
+		inf.NewDec(0, 1),
+		inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1),
+		inf.NewDec(2, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}},
+	{inf.RoundHalfDown, [...]*inf.Dec{
+		inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0),
+		inf.NewDec(-2, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
+		inf.NewDec(-1, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
+		inf.NewDec(0, 1),
+		inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(1, 1),
+		inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(2, 1)}},
+	{inf.RoundHalfUp, [...]*inf.Dec{
+		inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0),
+		inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-1, 1),
+		inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(0, 1),
+		inf.NewDec(0, 1),
+		inf.NewDec(0, 1), inf.NewDec(1, 1), inf.NewDec(1, 1),
+		inf.NewDec(1, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}},
+	{inf.RoundHalfEven, [...]*inf.Dec{
+		inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0),
+		inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-1, 1),
+		inf.NewDec(-1, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
+		inf.NewDec(0, 1),
+		inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(1, 1),
+		inf.NewDec(1, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}},
+	{inf.RoundFloor, [...]*inf.Dec{
+		inf.NewDec(1, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(1, 0),
+		inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-2, 1),
+		inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
+		inf.NewDec(0, 1),
+		inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
+		inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1)}},
+	{inf.RoundCeil, [...]*inf.Dec{
+		inf.NewDec(2, 0), inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(2, 0),
+		inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
+		inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
+		inf.NewDec(0, 1),
+		inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1),
+		inf.NewDec(2, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}},
 }
 }
 
 
 func TestDecRounders(t *testing.T) {
 func TestDecRounders(t *testing.T) {
 	for i, a := range decRounderResults {
 	for i, a := range decRounderResults {
 		for j, input := range decRounderInputs {
 		for j, input := range decRounderInputs {
-			q := new(Dec).Set(input.quo)
+			q := new(inf.Dec).Set(input.quo)
 			rA, rB := new(big.Int).Set(input.rA), new(big.Int).Set(input.rB)
 			rA, rB := new(big.Int).Set(input.rA), new(big.Int).Set(input.rB)
-			res := a.rounder.Round(new(Dec), q, rA, rB)
+			res := a.rounder.Round(new(inf.Dec), q, rA, rB)
 			if a.results[j] == nil && res == nil {
 			if a.results[j] == nil && res == nil {
 				continue
 				continue
 			}
 			}