mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-12 05:21:58 +00:00
Merge pull request #117411 from tenzen-y/add-multiply-method
quantity: Add multiplication methods
This commit is contained in:
commit
52cba2d8d8
@ -203,6 +203,44 @@ func (a *int64Amount) Sub(b int64Amount) bool {
|
||||
return a.Add(int64Amount{value: -b.value, scale: b.scale})
|
||||
}
|
||||
|
||||
// Mul multiplies the provided b to the current amount, or
|
||||
// returns false if overflow or underflow would result.
|
||||
func (a *int64Amount) Mul(b int64) bool {
|
||||
switch {
|
||||
case a.value == 0:
|
||||
return true
|
||||
case b == 0:
|
||||
a.value = 0
|
||||
a.scale = 0
|
||||
return true
|
||||
case a.scale == 0:
|
||||
c, ok := int64Multiply(a.value, b)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
a.value = c
|
||||
case a.scale > 0:
|
||||
c, ok := int64Multiply(a.value, b)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok = positiveScaleInt64(c, a.scale); !ok {
|
||||
return false
|
||||
}
|
||||
a.value = c
|
||||
default:
|
||||
c, ok := int64Multiply(a.value, b)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok = negativeScaleInt64(c, -a.scale); !ok {
|
||||
return false
|
||||
}
|
||||
a.value = c
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision
|
||||
// was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6.
|
||||
func (a int64Amount) AsScale(scale Scale) (int64Amount, bool) {
|
||||
|
@ -88,6 +88,49 @@ func TestInt64AmountAdd(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64AmountMul(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
a int64Amount
|
||||
b int64
|
||||
c int64Amount
|
||||
ok bool
|
||||
}{
|
||||
{int64Amount{value: 100, scale: 1}, 1000, int64Amount{value: 100000, scale: 1}, true},
|
||||
{int64Amount{value: 100, scale: -1}, 1000, int64Amount{value: 100000, scale: -1}, true},
|
||||
{int64Amount{value: 1, scale: 100}, 10, int64Amount{value: 1, scale: 100}, false},
|
||||
{int64Amount{value: 1, scale: -100}, 10, int64Amount{value: 1, scale: -100}, false},
|
||||
{int64Amount{value: -5, scale: 2}, 500, int64Amount{value: -2500, scale: 2}, true},
|
||||
{int64Amount{value: -5, scale: -2}, 500, int64Amount{value: -2500, scale: -2}, true},
|
||||
{int64Amount{value: 0, scale: 1}, 0, int64Amount{value: 0, scale: 1}, true},
|
||||
|
||||
{int64Amount{value: mostPositive, scale: -1}, 10, int64Amount{value: mostPositive, scale: -1}, false},
|
||||
{int64Amount{value: mostPositive, scale: -1}, 0, int64Amount{value: 0, scale: 0}, true},
|
||||
{int64Amount{value: mostPositive, scale: 0}, 1, int64Amount{value: mostPositive, scale: 0}, true},
|
||||
{int64Amount{value: mostPositive / 10, scale: 1}, 10, int64Amount{value: mostPositive / 10, scale: 1}, false},
|
||||
{int64Amount{value: mostPositive, scale: 0}, -1, int64Amount{value: -mostPositive, scale: 0}, true},
|
||||
{int64Amount{value: mostNegative, scale: 0}, 1, int64Amount{value: mostNegative, scale: 0}, true},
|
||||
{int64Amount{value: mostNegative, scale: 1}, 0, int64Amount{value: 0, scale: 0}, true},
|
||||
{int64Amount{value: mostNegative, scale: 1}, 1, int64Amount{value: mostNegative, scale: 1}, false},
|
||||
} {
|
||||
c := test.a
|
||||
ok := c.Mul(test.b)
|
||||
if ok && !test.ok {
|
||||
t.Errorf("unextected success: %v", c)
|
||||
} else if !ok && test.ok {
|
||||
t.Errorf("unexpeted failure: %v", c)
|
||||
} else if ok {
|
||||
if c != test.c {
|
||||
t.Errorf("%v: unexpected result: %d", test, c)
|
||||
}
|
||||
} else {
|
||||
if c != test.a {
|
||||
t.Errorf("%v: overflow multiplication mutated source: %d", test, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64AsCanonicalString(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
value int64
|
||||
|
@ -592,6 +592,16 @@ func (q *Quantity) Sub(y Quantity) {
|
||||
q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec())
|
||||
}
|
||||
|
||||
// Mul multiplies the provided y to the current value.
|
||||
// It will return false if the result is inexact. Otherwise, it will return true.
|
||||
func (q *Quantity) Mul(y int64) bool {
|
||||
q.s = ""
|
||||
if q.d.Dec == nil && q.i.Mul(y) {
|
||||
return true
|
||||
}
|
||||
return q.ToDec().d.Dec.Mul(q.d.Dec, inf.NewDec(y, inf.Scale(0))).UnscaledBig().IsInt64()
|
||||
}
|
||||
|
||||
// Cmp returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
|
||||
// quantity is greater than y.
|
||||
func (q *Quantity) Cmp(y Quantity) int {
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
@ -32,15 +33,29 @@ import (
|
||||
inf "gopkg.in/inf.v0"
|
||||
)
|
||||
|
||||
var (
|
||||
bigMostPositive = big.NewInt(mostPositive)
|
||||
bigMostNegative = big.NewInt(mostNegative)
|
||||
)
|
||||
|
||||
func dec(i int64, exponent int) infDecAmount {
|
||||
// See the below test-- scale is the negative of an exponent.
|
||||
return infDecAmount{inf.NewDec(i, inf.Scale(-exponent))}
|
||||
}
|
||||
|
||||
func bigDec(i *big.Int, exponent int) infDecAmount {
|
||||
// See the below test-- scale is the negative of an exponent.
|
||||
return infDecAmount{inf.NewDecBig(i, inf.Scale(-exponent))}
|
||||
}
|
||||
|
||||
func decQuantity(i int64, exponent int, format Format) Quantity {
|
||||
return Quantity{d: dec(i, exponent), Format: format}
|
||||
}
|
||||
|
||||
func bigDecQuantity(i *big.Int, exponent int, format Format) Quantity {
|
||||
return Quantity{d: bigDec(i, exponent), Format: format}
|
||||
}
|
||||
|
||||
func intQuantity(i int64, exponent Scale, format Format) Quantity {
|
||||
return Quantity{i: int64Amount{value: i, scale: exponent}, Format: format}
|
||||
}
|
||||
@ -67,6 +82,38 @@ func TestDec(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBigDec(t *testing.T) {
|
||||
table := []struct {
|
||||
got infDecAmount
|
||||
expect string
|
||||
}{
|
||||
{bigDec(big.NewInt(1), 0), "1"},
|
||||
{bigDec(big.NewInt(1), 1), "10"},
|
||||
{bigDec(big.NewInt(5), 2), "500"},
|
||||
{bigDec(big.NewInt(8), 3), "8000"},
|
||||
{bigDec(big.NewInt(2), 0), "2"},
|
||||
{bigDec(big.NewInt(1), -1), "0.1"},
|
||||
{bigDec(big.NewInt(3), -2), "0.03"},
|
||||
{bigDec(big.NewInt(4), -3), "0.004"},
|
||||
{bigDec(big.NewInt(0).Add(bigMostPositive, big.NewInt(1)), 0), "9223372036854775808"},
|
||||
{bigDec(big.NewInt(0).Add(bigMostPositive, big.NewInt(1)), 1), "92233720368547758080"},
|
||||
{bigDec(big.NewInt(0).Add(bigMostPositive, big.NewInt(1)), 2), "922337203685477580800"},
|
||||
{bigDec(big.NewInt(0).Add(bigMostPositive, big.NewInt(1)), -1), "922337203685477580.8"},
|
||||
{bigDec(big.NewInt(0).Add(bigMostPositive, big.NewInt(1)), -2), "92233720368547758.08"},
|
||||
{bigDec(big.NewInt(0).Sub(bigMostNegative, big.NewInt(1)), 0), "-9223372036854775809"},
|
||||
{bigDec(big.NewInt(0).Sub(bigMostNegative, big.NewInt(1)), 1), "-92233720368547758090"},
|
||||
{bigDec(big.NewInt(0).Sub(bigMostNegative, big.NewInt(1)), 2), "-922337203685477580900"},
|
||||
{bigDec(big.NewInt(0).Sub(bigMostNegative, big.NewInt(1)), -1), "-922337203685477580.9"},
|
||||
{bigDec(big.NewInt(0).Sub(bigMostNegative, big.NewInt(1)), -2), "-92233720368547758.09"},
|
||||
}
|
||||
|
||||
for _, item := range table {
|
||||
if e, a := item.expect, item.got.Dec.String(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestQuantityParseZero ensures that when a 0 quantity is passed, its string value is 0
|
||||
func TestQuantityParseZero(t *testing.T) {
|
||||
zero := MustParse("0")
|
||||
@ -1137,6 +1184,58 @@ func TestAdd(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMul(t *testing.T) {
|
||||
tests := []struct {
|
||||
a Quantity
|
||||
b int64
|
||||
expected Quantity
|
||||
ok bool
|
||||
}{
|
||||
{decQuantity(10, 0, DecimalSI), 10, decQuantity(100, 0, DecimalSI), true},
|
||||
{decQuantity(10, 0, DecimalSI), 1, decQuantity(10, 0, DecimalSI), true},
|
||||
{decQuantity(10, 0, BinarySI), 1, decQuantity(10, 0, BinarySI), true},
|
||||
{Quantity{Format: DecimalSI}, 50, decQuantity(0, 0, DecimalSI), true},
|
||||
{decQuantity(50, 0, DecimalSI), 0, decQuantity(0, 0, DecimalSI), true},
|
||||
{Quantity{Format: DecimalSI}, 0, decQuantity(0, 0, DecimalSI), true},
|
||||
|
||||
{decQuantity(10, 0, DecimalSI), -10, decQuantity(-100, 0, DecimalSI), true},
|
||||
{decQuantity(-10, 0, DecimalSI), 1, decQuantity(-10, 0, DecimalSI), true},
|
||||
{decQuantity(10, 0, BinarySI), -1, decQuantity(-10, 0, BinarySI), true},
|
||||
{decQuantity(-50, 0, DecimalSI), 0, decQuantity(0, 0, DecimalSI), true},
|
||||
{decQuantity(-50, 0, DecimalSI), -50, decQuantity(2500, 0, DecimalSI), true},
|
||||
{Quantity{Format: DecimalSI}, -50, decQuantity(0, 0, DecimalSI), true},
|
||||
{decQuantity(mostPositive, 0, DecimalSI), 0, decQuantity(0, 1, DecimalSI), true},
|
||||
{decQuantity(mostPositive, 0, DecimalSI), 1, decQuantity(mostPositive, 0, DecimalSI), true},
|
||||
{decQuantity(mostPositive, 0, DecimalSI), -1, decQuantity(-mostPositive, 0, DecimalSI), true},
|
||||
{decQuantity(mostPositive/2, 0, DecimalSI), 2, decQuantity((mostPositive/2)*2, 0, DecimalSI), true},
|
||||
{decQuantity(mostPositive/-2, 0, DecimalSI), -2, decQuantity((mostPositive/2)*2, 0, DecimalSI), true},
|
||||
{decQuantity(mostPositive, 0, DecimalSI), 2,
|
||||
bigDecQuantity(big.NewInt(0).Mul(bigMostPositive, big.NewInt(2)), 0, DecimalSI), false},
|
||||
{decQuantity(mostPositive, 0, DecimalSI), 10, decQuantity(mostPositive, 1, DecimalSI), false},
|
||||
{decQuantity(mostPositive, 0, DecimalSI), -10, decQuantity(-mostPositive, 1, DecimalSI), false},
|
||||
{decQuantity(mostNegative, 0, DecimalSI), 0, decQuantity(0, 1, DecimalSI), true},
|
||||
{decQuantity(mostNegative, 0, DecimalSI), 1, decQuantity(mostNegative, 0, DecimalSI), true},
|
||||
{decQuantity(mostNegative, 0, DecimalSI), -1,
|
||||
bigDecQuantity(big.NewInt(0).Add(bigMostPositive, big.NewInt(1)), 0, DecimalSI), false},
|
||||
{decQuantity(mostNegative/2, 0, DecimalSI), 2, decQuantity(mostNegative, 0, DecimalSI), true},
|
||||
{decQuantity(mostNegative/-2, 0, DecimalSI), -2, decQuantity(mostNegative, 0, DecimalSI), true},
|
||||
{decQuantity(mostNegative, 0, DecimalSI), 2,
|
||||
bigDecQuantity(big.NewInt(0).Mul(bigMostNegative, big.NewInt(2)), 0, DecimalSI), false},
|
||||
{decQuantity(mostNegative, 0, DecimalSI), 10, decQuantity(mostNegative, 1, DecimalSI), false},
|
||||
{decQuantity(mostNegative, 0, DecimalSI), -10,
|
||||
bigDecQuantity(big.NewInt(0).Add(bigMostPositive, big.NewInt(1)), 1, DecimalSI), false},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
if ok := test.a.Mul(test.b); test.ok != ok {
|
||||
t.Errorf("[%d] Expected ok: %t, got ok: %t", i, test.ok, ok)
|
||||
}
|
||||
if test.a.Cmp(test.expected) != 0 {
|
||||
t.Errorf("[%d] Expected %q, got %q", i, test.expected.AsDec().String(), test.a.AsDec().String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddSubRoundTrip(t *testing.T) {
|
||||
for k := -10; k <= 10; k++ {
|
||||
q := Quantity{Format: DecimalSI}
|
||||
|
Loading…
Reference in New Issue
Block a user