Change:
I'd like to add a multiplication method for the resource.Quantity. Currently, the resource package provides helper methods to calculate Quantity, such as and : Batch workloads often replicate the same PodTemplate, and controllers calculate the resources needed for all containers. In that case, It is inconvenient to call the function as many times as podTemplate, so I would like to create a helper function for multiplication.
/cc /sig api-machinary /wg batch
The label(s) cannot be applied, because the repository doesn't have them. <detailsIn response to : /cc /sig api-machinary /wg batch </details
/sig api-machinery /wg batch
Do you have an example of usage for these utilities? Just curious?
/triage accepted
Sorry for the late response. Taking k-sigs/kueue as an example, I assumed the below: It helps the controllers for batch workloads such as k-sigs/kueue, k-sigs/jobset, kubeflow/mpi-operator, and kubeflow/training-operator. I'm thinking of implementing this function once the code freeze term is finished.
/assign
Hi, may i take this up?
I took this one, and working on this now.

Discussion:
return a.Add(int64Amount{value: -b.value, scale: b.scale}) } <ins> // 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 } </ins> // 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) {

} } } <ins> 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) } } } } </ins> func TestInt64AsCanonicalString(t *testing.T) { for _, test := range []struct { value    int64

q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec()) } <ins> // 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() } </ins> // 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 {

"encoding/json" "fmt" "math" <ins> "math/big" </ins> "math/rand" "os" "strings"

inf "gopkg.in/inf.v0" ) <ins> var ( bigMostPositive = big.NewInt(mostPositive) bigMostNegative = big.NewInt(mostNegative) ) </ins> 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))} } <ins> 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))} } </ins> func decQuantity(i int64, exponent int, format Format) Quantity { return Quantity{d: dec(i, exponent), Format: format} } <ins> func bigDecQuantity(i *big.Int, exponent int, format Format) Quantity { return Quantity{d: bigDec(i, exponent), Format: format} } </ins> func intQuantity(i int64, exponent Scale, format Format) Quantity { return Quantity{i: int64Amount{value: i, scale: exponent}, Format: format} }

} } <ins> 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) } } } </ins> // TestQuantityParseZero ensures that when a 0 quantity is passed, its string value is 0 func TestQuantityParseZero(t *testing.T) { zero := MustParse("0")

} } <ins> 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()) } } } </ins> func TestAddSubRoundTrip(t *testing.T) { for k := -10; k <= 10; k++ { q := Quantity{Format: DecimalSI}