Functional Weave
Code in Rust

math.basis-points@2.0.0

README.md

2,600 bytes · view raw

# math.basis-points

100 basis points is 1 percent is a ratio of 0.01. The three units differ only
by powers of ten, so converting between them is moving a decimal point, and
`convertRate` does exactly that on the text of the number. `"0.07"` as a ratio
is `"7"` percent, where `0.07 * 100` in floating point is `7.000000000000001`.

Values are decimal strings in and out, never floats, so any rate a person can
write down converts without loss and without a size limit. Output is the
shortest form: no leading zeros, no trailing fractional zeros, no trailing
point, and zero is `"0"` (never `"-0"`).

Input is strict: an optional leading `-`, digits, and optionally `.` followed
by digits. `"12.5%"`, `"+5"`, `".5"`, `"5."`, `"1e3"`, `"1,5"` and spaces are
all errors. Strip a `%` sign before calling; this is not a parser for
free-form text.

The registry keeps rates as integer basis points, so two functions cover the
common edges. `toBasisPoints(value, unit)` returns an integer and refuses a
rate that is not a whole number of basis points (12.345% is 1234.5 basis
points, which no integer holds; rounding it is the caller's policy) or is
beyond ±(2^53 - 1). `fromBasisPoints(bp, unit)` renders an integer
basis-point rate as the shortest decimal string in another unit.

This is a group of three functions, each in its own file. `toBasisPoints` and
`fromBasisPoints` are built on `convertRate`, so installing either with
`only=` brings `convertRate` too.

## What changed from 1.0.0

1.0.0 was one function, `convertRate`, with `toBasisPoints` and
`fromBasisPoints` exported beside it but unpinned: no signature in the
manifest and no vectors. 2.0.0 is a group in which both are published
functions with their own signatures and vectors. `convertRate` is unchanged
and keeps every 1.0.0 vector.

`fromBasisPoints` changed behaviour, because the three languages did not
agree on it in 1.0.0: TypeScript refused a value beyond ±(2^53 - 1) and a
fraction ("basisPoints must be a safe integer"), Python refused only a
non-integer (with a different message) and converted any size, and Rust
converted any `i64`. In 2.0.0 all three refuse a fraction with
"basisPoints must be an integer" and a value beyond ±(2^53 - 1) with
"basisPoints is outside the safe integer range". `toBasisPoints` gives the
same answers and errors as before.

That behaviour change, and the move to one module per function (the group
module `math_basis_points` still re-exports all three; the Python module no
longer exports its `MAX_SAFE` constant), make this a major version.
Nothing in the registry depended on 1.0.0.