https://github.com/mitranim/frac
Missing feature of Go stdlib: integers ↔︎ fractional numeric strings, without rounding errors or bignums. Arbitrary fraction precision and radix.
https://github.com/mitranim/frac
bignum decimal fractional golang
Last synced: 9 months ago
JSON representation
Missing feature of Go stdlib: integers ↔︎ fractional numeric strings, without rounding errors or bignums. Arbitrary fraction precision and radix.
- Host: GitHub
- URL: https://github.com/mitranim/frac
- Owner: mitranim
- License: unlicense
- Created: 2021-03-05T21:20:04.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2023-07-10T09:11:55.000Z (over 2 years ago)
- Last Synced: 2025-04-26T06:56:56.288Z (9 months ago)
- Topics: bignum, decimal, fractional, golang
- Language: Go
- Homepage:
- Size: 8.79 KB
- Stars: 3
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
Awesome Lists containing this project
README
## Overview
Missing feature of the Go standard library: parsing and formatting `int64` as a fractional numeric string, _without any rounding or bignums_, by using a fixed fraction size. Supports arbitrary radixes from 2 to 36.
For example:
```
"123" <- frac 2, radix 10 -> 123_00
"123" <- frac 3, radix 10 -> 123_000
"123.45" <- frac 2, radix 10 -> 123_45
"123.45" <- frac 3, radix 10 -> 123_450
"123.456" <- frac 2, radix 10 ->
"123.456" <- frac 3, radix 10 -> 123_456
```
Performance on 64-bit machines is somewhat comparable to `strconv` and shouldn't be your bottleneck.
See API docs at https://pkg.go.dev/github.com/mitranim/frac.
## Why
* You use integers for money.
* You deal with external APIs that use decimal strings for money.
* You want to avoid rounding errors.
* You don't want to deal with "big decimal" libraries.
Then `frac` is for you!
## Usage
Basic usage:
```golang
import "github.com/mitranim/frac"
func main() {
num, err := frac.ParseDec(`-123`, 2)
assert(err == nil && num == -123_00)
num, err = frac.ParseDec(`-123.00`, 2)
assert(err == nil && num == -123_00)
num, err = frac.ParseDec(`-123.45`, 2)
assert(err == nil && num == -123_45)
// Exponent exceeds allotted precision. Conversion is impossible.
num, err = frac.ParseDec(`-123.456`, 2)
assert(err != nil && num == 0)
}
func assert(ok bool) {if !ok {panic("unreachable")}}
```
Implementing a monetary type:
```golang
import "github.com/mitranim/frac"
type Cents int64
func (self *Cents) UnmarshalText(input []byte) error {
num, err := frac.UnmarshalDec(input, 2)
if err != nil {
return err
}
*self = Cents(num)
return nil
}
func (self Cents) MarshalText() ([]byte, error) {
return frac.AppendDec(nil, int64(self), 2)
}
```
The resulting type `Cents` is an integer, but when decoding and encoding text, it's represented as a fractional with 2 decimal points.
## Known Limitations
* The code is too assembly-like. Kinda like the standard library.
* No special support for unsigned integers.
* When formatting, fractional precision is limited to `64`. (Imagine allocating gigabytes of memory for `0.0...01`.)
## License
https://unlicense.org
## Misc
I'm receptive to suggestions. If this library _almost_ satisfies you but needs changes, open an issue or chat me up. Contacts: https://mitranim.com/#contacts