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

v1 source pure

Code generated by generator.go; DO NOT EDIT.

Readme 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.

Overview

Code generated by generator.go; DO NOT EDIT.

Functions 52

func MulDiv

1func MulDiv(a, b, c int64) int64
source

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

1func MulDivUp(a, b, c int64) int64
source

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.

Imports 1

  • math/bits stdlib

Source Files 6