PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/xmath/v1

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v1
Namespace
moul / xmath
Files
6 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/xmath/v1
gno
0.9

Files (6)

  • README.mdmarkdown
  • gnomod.tomltoml
  • muldiv.gnogno
  • xmath.gen.gnogno
  • muldiv_test.gnogno
  • xmath.gen_test.gnogno
README.mdPreviewRaw
# `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.

```go
xmath.MaxInt(3, 7)             // 7
xmath.ClampInt64(x, 0, 100)    // x, bounded to [0,100]
xmath.AbsFloat64(-2.5)         // 2.5
xmath.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`](../../../tools/xmathgen) and carry a `DO NOT EDIT` header.
Edit the generator, never the output:

```sh
go -C tools run ./xmathgen           # rewrite both files
go -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.

```go
xmath.MulDiv(pot, stake, total)    // this stake's cut, rounded toward zero
xmath.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.

<!-- BEGIN GNOCONTRACTS FOOTER (generated by `make readmes`; do not edit below) -->

---

Part of **[moul/gno-contracts](https://github.com/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](https://github.com/moul/gno-contracts/blob/main/DISCLAIMER.md).

<!-- END GNOCONTRACTS FOOTER -->

Functions

not supported for pure packages by the node (vm/qfuncs)

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.