From 4381eb7237e96d51caba7d4e81b93607e6822262 Mon Sep 17 00:00:00 2001 From: Yuki Iwai Date: Mon, 17 Apr 2023 23:46:03 +0900 Subject: [PATCH 1/6] quantity: Add multiplication methods Add multiplication functionality to Quantity. Signed-off-by: Yuki Iwai --- .../apimachinery/pkg/api/resource/amount.go | 44 +++++++++++++++++ .../pkg/api/resource/amount_test.go | 48 +++++++++++++++++++ .../apimachinery/pkg/api/resource/quantity.go | 13 +++++ .../pkg/api/resource/quantity_test.go | 22 +++++++++ 4 files changed, 127 insertions(+) diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount.go index a8866a43e10..298c45fc852 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount.go @@ -203,6 +203,50 @@ func (a *int64Amount) Sub(b int64Amount) bool { return a.Add(int64Amount{value: -b.value, scale: b.scale}) } +// Mul multiplies two int64Amounts together, matching scales. +// It will return false and not mutate a if overflow or underflow would result. +// Mul adds the value of a to itself n times. +// It will return false and not mutate a if overflow or underflow would result. +func (a *int64Amount) Mul(b int64Amount) bool { + switch { + case b.value == 0: + a.value = 0 + return true + case a.value == 0: + a.value = 0 + a.scale = b.scale + return true + case a.scale == b.scale: + c, ok := int64Multiply(a.value, b.value) + if !ok { + return false + } + a.value = c + case a.scale > b.scale: + c, ok := positiveScaleInt64(a.value, a.scale-b.scale) + if !ok { + return false + } + c, ok = int64Multiply(c, b.value) + if !ok { + return false + } + a.scale = b.scale + a.value = c + default: + c, ok := positiveScaleInt64(b.value, b.scale-a.scale) + if !ok { + return false + } + c, ok = int64Multiply(a.value, c) + if !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) { diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go index 8217cb1399c..942b6f83637 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go @@ -88,6 +88,54 @@ func TestInt64AmountAdd(t *testing.T) { } } } + +func TestInt64AmountMul(t *testing.T) { + for _, test := range []struct { + a, b, c int64Amount + ok bool + }{ + {int64Amount{value: 100, scale: 1}, int64Amount{value: 10, scale: 2}, int64Amount{value: 10000, scale: 1}, true}, + {int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 2}, int64Amount{value: 1000, scale: 1}, true}, + {int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 100}, int64Amount{value: 1, scale: 100}, false}, + {int64Amount{value: -5, scale: 2}, int64Amount{value: 50, scale: 1}, int64Amount{value: -2500, scale: 1}, true}, + {int64Amount{value: -5, scale: 2}, int64Amount{value: 5, scale: 2}, int64Amount{value: -25, scale: 2}, true}, + + {int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 1, scale: -1}, int64Amount{value: 9223372036854775807, scale: -1}, true}, + {int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 0, scale: -1}, int64Amount{value: 0, scale: -1}, true}, + {int64Amount{value: mostPositive / 10, scale: 1}, int64Amount{value: 10, scale: 0}, int64Amount{value: mostPositive, scale: -1}, false}, + } { + c := test.a + ok := c.Mul(test.b) + if ok != test.ok { + t.Errorf("%v: unexpected ok: %t", test, ok) + } + 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) + } + } + + // multiplication is commutative + c = test.b + if ok = c.Mul(test.a); ok != test.ok { + t.Errorf("%v: unexpected ok: %t", test, ok) + } + if ok { + if c != test.c { + t.Errorf("%v: unexpected result: %d", test, c) + } + } else { + if c != test.b { + t.Errorf("%v: overflow multiplication mutated source: %d", test, c) + } + } + } +} + func TestInt64AsCanonicalString(t *testing.T) { for _, test := range []struct { value int64 diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go index b47d554b3c5..4368cb5ca54 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go @@ -592,6 +592,19 @@ func (q *Quantity) Sub(y Quantity) { q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec()) } +// Mul multiplies the provided y quantity to the current value. If the current value is zero, +// the format of the quantity will be updated to the format of y. +func (q *Quantity) Mul(y Quantity) { + q.s = "" + if q.IsZero() { + q.Format = y.Format + } + if q.d.Dec == nil && y.d.Dec == nil && q.i.Mul(y.i) { + return + } + q.ToDec().d.Dec.Mul(q.d.Dec, y.AsDec()) +} + // 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 { diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go index 320477358c8..b0f3a4481b5 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go @@ -1137,6 +1137,28 @@ func TestAdd(t *testing.T) { } } +func TestMul(t *testing.T) { + tests := []struct { + a Quantity + b Quantity + expected Quantity + }{ + {decQuantity(10, 0, DecimalSI), decQuantity(1, 1, DecimalSI), decQuantity(100, 0, DecimalSI)}, + {decQuantity(10, 0, DecimalSI), decQuantity(1, 0, BinarySI), decQuantity(10, 0, DecimalSI)}, + {decQuantity(10, 0, BinarySI), decQuantity(1, 0, DecimalSI), decQuantity(10, 0, BinarySI)}, + {Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI), decQuantity(0, 0, DecimalSI)}, + {decQuantity(50, 0, DecimalSI), Quantity{Format: DecimalSI}, decQuantity(0, 0, DecimalSI)}, + {Quantity{Format: DecimalSI}, Quantity{Format: DecimalSI}, decQuantity(0, 0, DecimalSI)}, + } + + for i, test := range tests { + test.a.Mul(test.b) + if test.a.Cmp(test.expected) != 0 { + t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), test.a.String()) + } + } +} + func TestAddSubRoundTrip(t *testing.T) { for k := -10; k <= 10; k++ { q := Quantity{Format: DecimalSI} From 79325b6178ddd6a677df85257e16583d5c00dafb Mon Sep 17 00:00:00 2001 From: Yuki Iwai Date: Sun, 7 May 2023 03:08:54 +0900 Subject: [PATCH 2/6] Multiply by a scalar Signed-off-by: Yuki Iwai --- .../apimachinery/pkg/api/resource/amount.go | 34 +++++++---------- .../pkg/api/resource/amount_test.go | 38 +++++++------------ .../apimachinery/pkg/api/resource/quantity.go | 15 +++----- .../pkg/api/resource/quantity_test.go | 23 ++++++----- 4 files changed, 47 insertions(+), 63 deletions(-) diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount.go index 298c45fc852..2eebec667d3 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount.go @@ -203,43 +203,37 @@ func (a *int64Amount) Sub(b int64Amount) bool { return a.Add(int64Amount{value: -b.value, scale: b.scale}) } -// Mul multiplies two int64Amounts together, matching scales. -// It will return false and not mutate a if overflow or underflow would result. -// Mul adds the value of a to itself n times. -// It will return false and not mutate a if overflow or underflow would result. -func (a *int64Amount) Mul(b int64Amount) bool { +// 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 b.value == 0: - a.value = 0 - return true case a.value == 0: - a.value = 0 - a.scale = b.scale return true - case a.scale == b.scale: - c, ok := int64Multiply(a.value, b.value) + 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 > b.scale: - c, ok := positiveScaleInt64(a.value, a.scale-b.scale) + case a.scale > 0: + c, ok := int64Multiply(a.value, b) if !ok { return false } - c, ok = int64Multiply(c, b.value) - if !ok { + if _, ok = positiveScaleInt64(c, a.scale); !ok { return false } - a.scale = b.scale a.value = c default: - c, ok := positiveScaleInt64(b.value, b.scale-a.scale) + c, ok := int64Multiply(a.value, b) if !ok { return false } - c, ok = int64Multiply(a.value, c) - if !ok { + if _, ok = negativeScaleInt64(c, -a.scale); !ok { return false } a.value = c diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go index 942b6f83637..08d2c193cec 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go @@ -91,18 +91,21 @@ func TestInt64AmountAdd(t *testing.T) { func TestInt64AmountMul(t *testing.T) { for _, test := range []struct { - a, b, c int64Amount - ok bool + a int64Amount + b int64 + c int64Amount + ok bool }{ - {int64Amount{value: 100, scale: 1}, int64Amount{value: 10, scale: 2}, int64Amount{value: 10000, scale: 1}, true}, - {int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 2}, int64Amount{value: 1000, scale: 1}, true}, - {int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 100}, int64Amount{value: 1, scale: 100}, false}, - {int64Amount{value: -5, scale: 2}, int64Amount{value: 50, scale: 1}, int64Amount{value: -2500, scale: 1}, true}, - {int64Amount{value: -5, scale: 2}, int64Amount{value: 5, scale: 2}, int64Amount{value: -25, scale: 2}, true}, + {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: mostPositive, scale: -1}, int64Amount{value: 1, scale: -1}, int64Amount{value: 9223372036854775807, scale: -1}, true}, - {int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 0, scale: -1}, int64Amount{value: 0, scale: -1}, true}, - {int64Amount{value: mostPositive / 10, scale: 1}, int64Amount{value: 10, scale: 0}, int64Amount{value: mostPositive, scale: -1}, false}, + {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 / 10, scale: 1}, 10, int64Amount{value: mostPositive / 10, scale: 1}, false}, } { c := test.a ok := c.Mul(test.b) @@ -118,21 +121,6 @@ func TestInt64AmountMul(t *testing.T) { t.Errorf("%v: overflow multiplication mutated source: %d", test, c) } } - - // multiplication is commutative - c = test.b - if ok = c.Mul(test.a); ok != test.ok { - t.Errorf("%v: unexpected ok: %t", test, ok) - } - if ok { - if c != test.c { - t.Errorf("%v: unexpected result: %d", test, c) - } - } else { - if c != test.b { - t.Errorf("%v: overflow multiplication mutated source: %d", test, c) - } - } } } diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go index 4368cb5ca54..69f1bc336d3 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go @@ -592,17 +592,14 @@ func (q *Quantity) Sub(y Quantity) { q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec()) } -// Mul multiplies the provided y quantity to the current value. If the current value is zero, -// the format of the quantity will be updated to the format of y. -func (q *Quantity) Mul(y Quantity) { +// 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.IsZero() { - q.Format = y.Format + if q.d.Dec == nil && q.i.Mul(y) { + return true } - if q.d.Dec == nil && y.d.Dec == nil && q.i.Mul(y.i) { - return - } - q.ToDec().d.Dec.Mul(q.d.Dec, y.AsDec()) + 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 diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go index b0f3a4481b5..21e079ed4c7 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go @@ -1140,21 +1140,26 @@ func TestAdd(t *testing.T) { func TestMul(t *testing.T) { tests := []struct { a Quantity - b Quantity + b int64 expected Quantity + ok bool }{ - {decQuantity(10, 0, DecimalSI), decQuantity(1, 1, DecimalSI), decQuantity(100, 0, DecimalSI)}, - {decQuantity(10, 0, DecimalSI), decQuantity(1, 0, BinarySI), decQuantity(10, 0, DecimalSI)}, - {decQuantity(10, 0, BinarySI), decQuantity(1, 0, DecimalSI), decQuantity(10, 0, BinarySI)}, - {Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI), decQuantity(0, 0, DecimalSI)}, - {decQuantity(50, 0, DecimalSI), Quantity{Format: DecimalSI}, decQuantity(0, 0, DecimalSI)}, - {Quantity{Format: DecimalSI}, Quantity{Format: DecimalSI}, decQuantity(0, 0, DecimalSI)}, + {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(mostPositive, 0, DecimalSI), 10, decQuantity(mostPositive, 1, DecimalSI), false}, } for i, test := range tests { - test.a.Mul(test.b) + 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.String(), test.a.String()) + t.Errorf("[%d] Expected %q, got %q", i, test.expected.AsDec().String(), test.a.AsDec().String()) } } } From 685ae024332a603969cd054734cda450099f0b75 Mon Sep 17 00:00:00 2001 From: Yuki Iwai Date: Sat, 10 Jun 2023 02:17:22 +0900 Subject: [PATCH 3/6] Add more unit tests Signed-off-by: Yuki Iwai --- .../k8s.io/apimachinery/pkg/api/resource/amount_test.go | 3 +++ .../apimachinery/pkg/api/resource/quantity_test.go | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go index 08d2c193cec..c2dec397869 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go @@ -106,6 +106,9 @@ func TestInt64AmountMul(t *testing.T) { {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 / 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: 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) diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go index 21e079ed4c7..90648b9b6bd 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go @@ -1151,7 +1151,16 @@ func TestMul(t *testing.T) { {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), 10, decQuantity(mostPositive, 1, DecimalSI), false}, + {decQuantity(mostNegative, 0, DecimalSI), 10, decQuantity(mostNegative, 1, DecimalSI), false}, + {decQuantity(mostPositive, 0, DecimalSI), -10, decQuantity(-mostPositive, 1, DecimalSI), false}, } for i, test := range tests { From 4de3e73b8ac160c0e95e5f7a94ec07a96d9f7832 Mon Sep 17 00:00:00 2001 From: Yuki Iwai Date: Sun, 11 Jun 2023 23:33:43 +0900 Subject: [PATCH 4/6] Add test cases for mostPositive and mostNegative Signed-off-by: Yuki Iwai --- .../pkg/api/resource/amount_test.go | 2 + .../pkg/api/resource/quantity_test.go | 67 ++++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go index c2dec397869..0935016e8db 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go @@ -105,8 +105,10 @@ func TestInt64AmountMul(t *testing.T) { {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}, } { diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go index 90648b9b6bd..646caee7b78 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity_test.go @@ -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") @@ -1157,10 +1204,26 @@ func TestMul(t *testing.T) { {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(mostNegative, 0, DecimalSI), 10, decQuantity(mostNegative, 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 { From fb2e28b0702f43af76329caa43459685b3ee5529 Mon Sep 17 00:00:00 2001 From: Yuki Iwai Date: Sat, 14 Oct 2023 05:12:04 +0900 Subject: [PATCH 5/6] Verify more carefully the results in the TestInt64AmountMul Signed-off-by: Yuki Iwai --- .../k8s.io/apimachinery/pkg/api/resource/amount_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go index 0935016e8db..d31e0b92967 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go @@ -114,10 +114,11 @@ func TestInt64AmountMul(t *testing.T) { } { c := test.a ok := c.Mul(test.b) - if ok != test.ok { - t.Errorf("%v: unexpected ok: %t", test, ok) - } - if ok { + 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) } From ddcbae734af8d372414bf891b8a45b64c1f9fad7 Mon Sep 17 00:00:00 2001 From: Yuki Iwai Date: Sat, 14 Oct 2023 05:54:15 +0900 Subject: [PATCH 6/6] =?UTF-8?q?Add=20a=200=20=C3=97=200=20case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yuki Iwai --- staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go index d31e0b92967..a6c4054b989 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/resource/amount_test.go @@ -102,6 +102,7 @@ func TestInt64AmountMul(t *testing.T) { {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},