Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

README.md

3.79 Kb · 90 lines

gno.land/p/nym-moultest123/xmath

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.

Adding these is a non-breaking change, so xmath stays at its current version and every existing importer is untouched.


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.