v1 source pure
Code generated by generator.go; DO NOT EDIT.
View source
gno.land/p/moul/xmath/v1
Max, Min, Clamp, Abs and Sign for every built-in numeric type, one
concrete function per type. Gno has no generics, so the alternative is writing
the same three-line helper again in each realm.
1xmath.MaxInt(3, 7) // 7
2xmath.ClampInt64(x, 0, 100) // x, bounded to [0,100]
3xmath.AbsFloat64(-2.5) // 2.5
4xmath.SignInt(-9) // -1
| type | functions |
|---|---|
int, int8, int16, int32, int64 |
Max, Min, Clamp, Abs, Sign |
uint, uint8, uint16, uint32, uint64 |
Max, Min, Clamp |
float32, float64 |
Max, Min, Clamp, Abs, Sign |
Unsigned types get no Abs or Sign: both are trivially themselves and 1, and
offering them would only invite an overflow bug at the call site.
The name is the type suffix: MaxInt8, MinUint64, ClampFloat32.
Sign returns -1, 0 or 1. Clamp does not validate its bounds: calling it
with min > max returns one bound or the other depending on the value, so
check the bounds yourself if they are computed.
Generated
xmath.gen.gno and xmath.gen_test.gno are written by
tools/xmathgen and carry a DO NOT EDIT header.
Edit the generator, never the output:
1go -C tools run ./xmathgen # rewrite both files
2go -C tools run ./xmathgen -check # fail if they are stale
Adding a type is one row in the types table in tools/xmathgen/main.go; it
expands to 5 functions plus their tests.
The header used to name a generator.go that was never committed, so it was a
rule nobody could follow. The generator above was reconstructed from the output
it describes and reproduces both committed files byte for byte, which
go test ./tools/xmathgen asserts on every run.
MulDiv: the proportional share, through a 128-bit intermediate
Hand-written rather than generated, in muldiv.gno, because it is one function
and not a per-type family.
1xmath.MulDiv(pot, stake, total) // this stake's cut, rounded toward zero
2xmath.MulDivUp(pot, stake, total) // the same ratio, rounded away from zero
a*b/c computes a*b first, and an int64 product that does not fit wraps
silently to a plausible number. Measured with a = 2^62, b = 4, c = 8:
the true share is 2305843009213693952 and the naive form answers 0,
because 2^62 * 4 is exactly 2^64 and wraps to zero. Nothing fails, nothing
logs, and a payout split is simply wrong.
Ten realms deployed on gnoland-1 carry their own copy of this, all reaching
for math/bits the same way: bubblerumble (several versions) and kourt,
whose mulDiv128 is the same function with its own panic strings. It had no
owner in p/moul or p/nt until now.
MulDiv panics rather than returning a wrong number: on a negative operand, on
a denominator at or below zero, and on a quotient that does not fit.
MulDivUp exists because rounding is a money question, not a style one.
Rounding a fee down and a payout up is how a pool pays out more than it holds.
Use MulDiv for what someone receives and MulDivUp for what someone owes;
TestRoundingDirectionIsTheMoneyQuestion pins that they never differ by more
than one and never cross.
Why v1 even though adding a function is non-breaking
It is non-breaking for this repo, and that is not the constraint that
matters. p/ packages are always public, and a live public path can never be
redeployed, so functions added in place at v0 reach main and never reach the
chain. v1 is the only way MulDiv becomes importable by anybody.
The bump is free here: xmath has zero importers, in this repo and across
every package deployed on gnoland-1. v0 stays resolvable for nobody in
particular.
Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.
⚠️ Disclaimer: provided as-is, without warranty; not security-audited. Full disclaimer: DISCLAIMER.
Code generated by generator.go; DO NOT EDIT.
52
func AbsFloat64
func AbsInt
func AbsInt16
func AbsInt32
func AbsInt64
func AbsInt8
func ClampFloat32
func ClampFloat64
func ClampInt
func ClampInt16
func ClampInt32
func ClampInt64
func ClampInt8
func ClampUint
func ClampUint16
func ClampUint32
func ClampUint64
func ClampUint8
func MaxFloat32
Float32 helpers
func MaxFloat64
Float64 helpers
func MaxInt
Int helpers
func MaxInt16
Int16 helpers
func MaxInt32
Int32 helpers
func MaxInt64
Int64 helpers
func MaxInt8
Int8 helpers
func MaxUint
Uint helpers
func MaxUint16
Uint16 helpers
func MaxUint32
Uint32 helpers
func MaxUint64
Uint64 helpers
func MaxUint8
Uint8 helpers
func MinFloat32
func MinFloat64
func MinInt
func MinInt16
func MinInt32
func MinInt64
func MinInt8
func MinUint
func MinUint16
func MinUint32
func MinUint64
func MinUint8
func MulDiv
MulDiv returns a*b/c computed through a 128-bit intermediate, so the product does not have to fit in an int64. It is the proportional-share calculation: "this account's cut of the pot", "this stake's slice of the rewards".
The naive a*b/c silently wraps when a*b exceeds an int64, and it wraps to a plausible-looking number rather than to an obvious one, which is how a payout split leaks money without anything failing. Ten realms deployed on gnoland-1 carry their own copy of this function for exactly that reason, and every one of them reaches for math/bits the same way.
MulDiv panics rather than returning a wrong number:
- a or b negative, or c at or below zero: the domain is unsigned ratios, and a negative share is a caller bug, not a value to propagate.
- the quotient not fitting in an int64.
Rounding is toward zero, like integer division. See MulDivUp when the remainder must favour the payer instead.
func MulDivUp
MulDivUp is MulDiv rounding away from zero when the division is not exact.
Which way to round is a money question, not a style one: rounding a fee down and a payout up is how a pool pays out more than it holds. Use MulDiv for what someone receives and MulDivUp for what someone owes.
func SignFloat32
func SignFloat64
func SignInt
func SignInt16
func SignInt32
func SignInt64
func SignInt8
1
- math/bits stdlib