var ErrZeroDenominator
ErrZeroDenominator is returned when a denominator of zero is requested.
Package fraction is exact rational arithmetic as a pure, reusable package: values are p/q with int64 numerator and de...
gno.land/p/moul/x/daily/fraction/v0Exact rational arithmetic — New, Int, Zero, Add, Sub, Mul,
Div, Neg, Cmp, Equal, String, Decimal.
Values are p/q with int64 numerator and denominator, always in lowest terms
with a positive denominator.
1import "gno.land/p/moul/x/daily/fraction/v0"
2
3third, _ := fraction.New(1, 3)
4sum, ok := third.Add(third) // 2/3, ok
5sum, ok = sum.Add(third) // exactly 1 — not 0.9999…
6fraction.Decimal(third, 5) // "0.33333"
This exists because there are no floats worth trusting on chain. 0.1 + 0.2
is not 0.3 in binary floating point, and a consensus system cannot afford an
answer that depends on rounding. A fraction is exact; it only becomes lossy at
the moment you ask for a decimal, and Decimal makes that moment explicit —
the caller chooses how much to lose and when.
Overflow is reported, never wrapped. Every operation returns ok=false on
int64 overflow rather than silently producing a wrapped numerator, which would
be a wrong answer that looks perfectly fine.
Cmp cross-multiplies, so comparison is exact too: 1/3 and 33333/100000 are
identical to five decimal places, and it still knows which is larger.
The sign always lives in the numerator, so 1/-2 and -1/2 are the same value.
The zero value of the type behaves as 0/1 rather than dividing by zero.
Live demo: r/moul/x/daily/fractiondemo
· render it at /r/moul/x/daily/fractiondemo/v0.
Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.
🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.
Package fraction is exact rational arithmetic as a pure, reusable package: values are p/q with int64 numerator and denominator, always kept in lowest terms with a positive denominator.
This exists because there are no floats worth trusting on chain. 0.1 + 0.2 is not 0.3 in binary floating point, and a consensus system cannot afford an answer that depends on rounding. A fraction is exact: one third really is one third, and only becomes lossy at the moment you ask for a decimal.
Every operation is checked for int64 overflow and returns ok=false rather than silently wrapping — a wrapped numerator would be a wrong answer that looks fine.
A live demo of this package is at r/moul/x/daily/fractiondemo(/r/moul/x/daily/fractiondemo/v0).
ErrZeroDenominator is returned when a denominator of zero is requested.
Decimal renders f with exactly places digits after the point, truncated toward zero. THIS is where exactness ends — 1/3 cannot be written in decimal, so the caller chooses how much to lose and when.
Int returns n as n/1.
New returns num/den reduced, or an error when den is zero.
Zero is 0/1.
Fraction is an exact rational number in lowest terms, denominator > 0.
Add returns f+g. ok is false on int64 overflow.
Cmp returns -1, 0 or +1 as f is less than, equal to, or greater than g. Compares by cross-multiplication, so it is exact — no decimal conversion.
Den returns the denominator, which is always > 0. The zero value of the type has den == 0, so treat it as 1 to keep an un-initialised Fraction usable.
Div returns f/g. ok is false on overflow or division by zero.
Equal reports exact equality.
IsZero reports whether f == 0.
Mul returns f*g. ok is false on int64 overflow.
Neg returns -f.
Num returns the numerator; Den the (always positive) denominator.
String renders "p/q", or just "p" when the denominator is 1.
Sub returns f-g. ok is false on int64 overflow.