Browse Source

revise Unscaled*(), docs

speter 13 năm trước cách đây
mục cha
commit
88978f6655
3 tập tin đã thay đổi với 85 bổ sung36 xóa
  1. 56 31
      dec.go
  2. 24 0
      dec_test.go
  3. 5 5
      rounder.go

+ 56 - 31
dec.go

@@ -15,12 +15,26 @@
 //  - conversions to and from float32/64 types
 //
 // Features considered for possible addition:
-//  + revise/add Unscaled(Big) to match SetUnscaled(Big) and NewDec(Big)
 //  + formatting options
 //  + Exp method
 //  + combined operations such as AddRound/MulAdd etc
 //  + exchanging data in decimal32/64/128 formats
 //
+// API Changes
+//
+// Compared to http://code.google.com/p/godec , the following APIs have changed:
+//
+//  godec              inf.Dec                 rationale
+//  ---------------------------------------------------------------------------
+//  NewDecInt64(u)     NewDec(u, 0)            favor common case for short API
+//  NewDec(u, s)       NewDecBig(b, i)         favor common case for short API
+//  z.SetUnscaled(u)   z.SetUnscaledBig(u)     favor common case for short API
+//  (n/a)              z.SetUnscaled(u)        favor common case for short API
+//  x.Unscaled()       x.UnscaledBig()         favor common case for short API
+//  (n/a)              x.Unscaled()            favor common case for short API
+//  z.Quo(x, y, s, r)  z.QuoRound(x, y, s, r)  consistency (combined operation)
+//  type Scaler        (unexported)            hide implementation details
+//
 package inf
 
 // TODO:
@@ -113,14 +127,14 @@ var exp10cache [64]big.Int = func() [64]big.Int {
 	return e10
 }()
 
-// NewDec allocates and returns a new Dec set to the given unscaled value and
-// scale.
+// NewDec allocates and returns a new Dec set to the given int64 unscaled value
+// and scale.
 func NewDec(unscaled int64, scale Scale) *Dec {
 	return new(Dec).SetUnscaled(unscaled).SetScale(scale)
 }
 
-// NewDecInt64 allocates and returns a new Dec set to the given int64 value with
-// scale 0.
+// NewDecBig allocates and returns a new Dec set to the given *big.Int unscaled
+// value and scale.
 func NewDecBig(unscaled *big.Int, scale Scale) *Dec {
 	return new(Dec).SetUnscaledBig(unscaled).SetScale(scale)
 }
@@ -130,8 +144,19 @@ func (x *Dec) Scale() Scale {
 	return x.scale
 }
 
-// Unscaled returns the unscaled value of x.
-func (x *Dec) Unscaled() *big.Int {
+// Unscaled returns the unscaled value of x for u and true for ok when the
+// unscaled value can be represented as int64; otherwise it returns an undefined
+// int64 value for u and false for ok. Use x.UnscaledBig().Int64() to avoid
+// checking the validity of the value when the check is known to be redundant.
+func (x *Dec) Unscaled() (u int64, ok bool) {
+	u = x.unscaled.Int64()
+	var i big.Int
+	ok = i.SetInt64(u).Cmp(&x.unscaled) == 0
+	return
+}
+
+// UnscaledBig returns the unscaled value of x as *big.Int.
+func (x *Dec) UnscaledBig() *big.Int {
 	return &x.unscaled
 }
 
@@ -162,7 +187,7 @@ func (z *Dec) SetUnscaledBig(unscaled *big.Int) *Dec {
 // It does nothing if z == x.
 func (z *Dec) Set(x *Dec) *Dec {
 	if z != x {
-		z.SetUnscaledBig(x.Unscaled())
+		z.SetUnscaledBig(x.UnscaledBig())
 		z.SetScale(x.Scale())
 	}
 	return z
@@ -175,13 +200,13 @@ func (z *Dec) Set(x *Dec) *Dec {
 //	+1 if x >  0
 //
 func (x *Dec) Sign() int {
-	return x.Unscaled().Sign()
+	return x.UnscaledBig().Sign()
 }
 
 // Neg sets z to -x and returns z.
 func (z *Dec) Neg(x *Dec) *Dec {
 	z.SetScale(x.Scale())
-	z.Unscaled().Neg(x.Unscaled())
+	z.UnscaledBig().Neg(x.UnscaledBig())
 	return z
 }
 
@@ -193,13 +218,13 @@ func (z *Dec) Neg(x *Dec) *Dec {
 //
 func (x *Dec) Cmp(y *Dec) int {
 	xx, yy := upscale(x, y)
-	return xx.Unscaled().Cmp(yy.Unscaled())
+	return xx.UnscaledBig().Cmp(yy.UnscaledBig())
 }
 
 // Abs sets z to |x| (the absolute value of x) and returns z.
 func (z *Dec) Abs(x *Dec) *Dec {
 	z.SetScale(x.Scale())
-	z.Unscaled().Abs(x.Unscaled())
+	z.UnscaledBig().Abs(x.UnscaledBig())
 	return z
 }
 
@@ -208,7 +233,7 @@ func (z *Dec) Abs(x *Dec) *Dec {
 func (z *Dec) Add(x, y *Dec) *Dec {
 	xx, yy := upscale(x, y)
 	z.SetScale(xx.Scale())
-	z.Unscaled().Add(xx.Unscaled(), yy.Unscaled())
+	z.UnscaledBig().Add(xx.UnscaledBig(), yy.UnscaledBig())
 	return z
 }
 
@@ -217,7 +242,7 @@ func (z *Dec) Add(x, y *Dec) *Dec {
 func (z *Dec) Sub(x, y *Dec) *Dec {
 	xx, yy := upscale(x, y)
 	z.SetScale(xx.Scale())
-	z.Unscaled().Sub(xx.Unscaled(), yy.Unscaled())
+	z.UnscaledBig().Sub(xx.UnscaledBig(), yy.UnscaledBig())
 	return z
 }
 
@@ -225,7 +250,7 @@ func (z *Dec) Sub(x, y *Dec) *Dec {
 // The scale of z is the sum of the scales of x and y.
 func (z *Dec) Mul(x, y *Dec) *Dec {
 	z.SetScale(x.Scale() + y.Scale())
-	z.Unscaled().Mul(x.Unscaled(), y.Unscaled())
+	z.UnscaledBig().Mul(x.UnscaledBig(), y.UnscaledBig())
 	return z
 }
 
@@ -294,19 +319,19 @@ func (z *Dec) quoRem(x, y *Dec, s Scale, useRem bool,
 	switch {
 	case shift > 0:
 		// increased scale: decimal-shift dividend left
-		ix = new(big.Int).Mul(x.Unscaled(), exp10(shift))
-		iy = y.Unscaled()
+		ix = new(big.Int).Mul(x.UnscaledBig(), exp10(shift))
+		iy = y.UnscaledBig()
 	case shift < 0:
 		// decreased scale: decimal-shift divisor left
-		ix = x.Unscaled()
-		iy = new(big.Int).Mul(y.Unscaled(), exp10(-shift))
+		ix = x.UnscaledBig()
+		iy = new(big.Int).Mul(y.UnscaledBig(), exp10(-shift))
 	default:
-		ix = x.Unscaled()
-		iy = y.Unscaled()
+		ix = x.UnscaledBig()
+		iy = y.UnscaledBig()
 	}
 	// save a copy of iy in case it to be overwritten with the result
 	iy2 := iy
-	if iy == z.Unscaled() {
+	if iy == z.UnscaledBig() {
 		iy2 = new(big.Int).Set(iy)
 	}
 	// set scale
@@ -314,12 +339,12 @@ func (z *Dec) quoRem(x, y *Dec, s Scale, useRem bool,
 	// set unscaled
 	if useRem {
 		// Int division
-		_, intr := z.Unscaled().QuoRem(ix, iy, new(big.Int))
+		_, intr := z.UnscaledBig().QuoRem(ix, iy, new(big.Int))
 		// set remainder
 		remNum.Set(intr)
 		remDen.Set(iy2)
 	} else {
-		z.Unscaled().Quo(ix, iy)
+		z.UnscaledBig().Quo(ix, iy)
 	}
 	return z, remNum, remDen
 }
@@ -333,7 +358,7 @@ func (s sclr) Scale(x, y *Dec) Scale {
 type scaleQuoExact struct{}
 
 func (sqe scaleQuoExact) Scale(x, y *Dec) Scale {
-	rem := new(big.Rat).SetFrac(x.Unscaled(), y.Unscaled())
+	rem := new(big.Rat).SetFrac(x.UnscaledBig(), y.UnscaledBig())
 	f2, f5 := factor2(rem.Denom()), factor(rem.Denom(), bigInt[5])
 	var f10 Scale
 	if f2 > f5 {
@@ -391,10 +416,10 @@ func (x *Dec) rescale(newScale Scale) *Dec {
 	switch {
 	case shift < 0:
 		e := exp10(-shift)
-		return NewDecBig(new(big.Int).Quo(x.Unscaled(), e), newScale)
+		return NewDecBig(new(big.Int).Quo(x.UnscaledBig(), e), newScale)
 	case shift > 0:
 		e := exp10(shift)
-		return NewDecBig(new(big.Int).Mul(x.Unscaled(), e), newScale)
+		return NewDecBig(new(big.Int).Mul(x.UnscaledBig(), e), newScale)
 	}
 	return x
 }
@@ -419,7 +444,7 @@ func (x *Dec) String() string {
 		return "<nil>"
 	}
 	scale := x.Scale()
-	s := []byte(x.Unscaled().String())
+	s := []byte(x.UnscaledBig().String())
 	if scale <= 0 {
 		if scale != 0 && x.unscaled.Sign() != 0 {
 			s = appendZeros(s, -scale)
@@ -501,7 +526,7 @@ loop:
 	} else {
 		z.SetScale(0)
 	}
-	_, ok := z.Unscaled().SetString(string(unscaled), 10)
+	_, ok := z.UnscaledBig().SetString(string(unscaled), 10)
 	if !ok {
 		return nil, fmt.Errorf("invalid decimal: %s", string(unscaled))
 	}
@@ -565,7 +590,7 @@ func scale(b []byte) (s Scale) {
 
 // GobEncode implements the gob.GobEncoder interface.
 func (x *Dec) GobEncode() ([]byte, error) {
-	buf, err := x.Unscaled().GobEncode()
+	buf, err := x.UnscaledBig().GobEncode()
 	if err != nil {
 		return nil, err
 	}
@@ -583,7 +608,7 @@ func (z *Dec) GobDecode(buf []byte) error {
 		return fmt.Errorf("Dec.GobDecode: encoding version %d not supported", b)
 	}
 	l := len(buf) - scaleSize - 1
-	err := z.Unscaled().GobDecode(buf[:l])
+	err := z.UnscaledBig().GobDecode(buf[:l])
 	if err != nil {
 		return err
 	}

+ 24 - 0
dec_test.go

@@ -132,6 +132,30 @@ func TestDecQuoRem(t *testing.T) {
 	}
 }
 
+var decUnscaledTests = []struct {
+	d  *Dec
+	u  int64 // ignored when ok == false
+	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},
+}
+
+func TestDecUnscaled(t *testing.T) {
+	for i, tt := range decUnscaledTests {
+		u, ok := tt.d.Unscaled()
+		if ok != tt.ok {
+			t.Errorf("#%d Unscaled: got %v, expected %v", i, ok, tt.ok)
+		} else if ok && u != tt.u {
+			t.Errorf("#%d Unscaled: got %v, expected %v", i, u, tt.u)
+		}
+	}
+}
+
 var decRoundTests = [...]struct {
 	in  *Dec
 	s   Scale

+ 5 - 5
rounder.go

@@ -253,7 +253,7 @@ var roundUp = rndr{true,
 	func(z, q *Dec, rA, rB *big.Int) *Dec {
 		z.Set(q)
 		if rA.Sign() != 0 {
-			z.Unscaled().Add(z.Unscaled(), intSign[rA.Sign()*rB.Sign()+1])
+			z.UnscaledBig().Add(z.UnscaledBig(), intSign[rA.Sign()*rB.Sign()+1])
 		}
 		return z
 	}}
@@ -274,13 +274,13 @@ func roundHalf(f func(c int, odd uint) (roundUp bool)) func(z, q *Dec, rA, rB *b
 			if s < 0 {
 				rA2.Neg(rA2)
 			}
-			roundUp = f(rA2.Cmp(rB)*srB, z.Unscaled().Bit(0))
+			roundUp = f(rA2.Cmp(rB)*srB, z.UnscaledBig().Bit(0))
 		} else {
 			// brA > brB-1 => |rA| > |rB/2|
 			roundUp = true
 		}
 		if roundUp {
-			z.Unscaled().Add(z.Unscaled(), intSign[s+1])
+			z.UnscaledBig().Add(z.UnscaledBig(), intSign[s+1])
 		}
 		return z
 	}
@@ -305,7 +305,7 @@ var roundFloor = rndr{true,
 	func(z, q *Dec, rA, rB *big.Int) *Dec {
 		z.Set(q)
 		if rA.Sign()*rB.Sign() < 0 {
-			z.Unscaled().Add(z.Unscaled(), intSign[0])
+			z.UnscaledBig().Add(z.UnscaledBig(), intSign[0])
 		}
 		return z
 	}}
@@ -314,7 +314,7 @@ var roundCeil = rndr{true,
 	func(z, q *Dec, rA, rB *big.Int) *Dec {
 		z.Set(q)
 		if rA.Sign()*rB.Sign() > 0 {
-			z.Unscaled().Add(z.Unscaled(), intSign[2])
+			z.UnscaledBig().Add(z.UnscaledBig(), intSign[2])
 		}
 		return z
 	}}