### 31 releases

Uses old Rust 2015

0.13.1 | Feb 24, 2023 |
---|---|

0.12.2 | Dec 4, 2022 |

0.12.1 | Oct 19, 2022 |

0.11.0 | Jun 18, 2022 |

0.1.0 | Jan 24, 2016 |

#**41** in Data structures

**234,482** downloads per month

Used in **114** crates
(34 directly)

**MIT/Apache**

475KB

11K
SLoC

# Fraction

## Lossless fractions and decimals; drop-in float replacement

# Features

- Fraction type, representing floats as fractions
- Decimal type, based on Fraction type with explicit precision
- Fractions are drop-in replacement for floats with the exception for NaN == NaN && NaN < NegInfinity, thus it's hasheable and orderable.
- Fractions are hashable and orderable, so they may be used in Sets, HashMaps and BTrees.
- DynaInt type, which is an int dynamically growing into heap. Performs checked math and avoids stack overflows.
- PostgreSQL integration for Numeric/Decimal type (with no extra memory allocations)
- Juniper integration for both fractions and decimals
- Support for generic integer conversions, such as

,`i8``->``u8`

and so on`usize``->``u8` - Lossless division with infinite precision and no memory allocations

# Documentation

# Examples

## Simple use:

`type` `F` `=` `fraction``::`Fraction`;` `//` choose the type accordingly with your needs (see prelude module docs)
`let` two `=` `F``::`from`(``0``)` `+` `2``;` `//` 0 + 2 = 2
`let` two_third `=` two `/` `3``;` `//` 2/3 = 0.666666[...]
`assert_eq!``(``F``::`from`(``2``)``,` two`)``;`
`assert_eq!``(``F``::`new`(``2``u64``,` `3``u64``)``,` two_third`)``;`
`assert_eq!``(``"`2/3`"``,` `format!``(``"``{}``"``,` two_third`)``)``;` `//` print as Fraction (by default)
`assert_eq!``(``"`0.6666`"``,` `format!``(``"``{:.4}``"``,` two_third`)``)``;` `//` format as decimal and print up to 4 digits after floating point

Decimal is implemented as a representation layer on top of Fraction. Thus, it is also lossless and may require explicit control over "precision" for comparison and formatting operations.

`type` `D` `=` `fraction``::`Decimal`;` `//` choose the type accordingly with your needs (see prelude module docs)
`let` result `=` `D``::`from`(``0.``5``)` `/` `0.``3``;`
`assert_eq!``(``format!``(``"``{}``"``,` result`)``,` `"`1.6`"``)``;` `//` calculation result uses precision of the operands
`assert_eq!``(``format!``(``"``{:.4}``"``,` result`)``,` `"`1.6666`"``)``;` `//` explicitly passing precision to format
`assert_eq!``(``"`1.6666`"``,` `format!``(``"``{}``"``,` result`.``set_precision``(``4``)``)``)``;` `//` the other way to set precision explicitly on Decimal

## Construct:

Fraction:

`use` `std``::``str``::`FromStr`;`
`use` `fraction``::``{`Fraction`,` Sign`}``;`
`fn` `main``(``)`` ``{`
`//` There are several ways to construct a fraction, depending on your use case
`let` f `=` `Fraction``::`new`(``1``u8``,` `2``u8``)``;` `//` constructs with numerator/denominator and normalizes the fraction (finds least common denominator)
`assert_eq!``(`f`,` `Fraction``::`new_generic`(``Sign``::`Plus`,` `1``i32``,` `2``u8``)``.``unwrap``(``)``)``;` `//` with numerator/denominator of different integer types
`assert_eq!``(`f`,` `Fraction``::`from`(``0.``5``)``)``;` `//` convert from float (f32, f64)
`assert_eq!``(`f`,` `Fraction``::`from_str`(``"`0.5`"``)``.``unwrap``(``)``)``;` `//` parse a string
`assert_eq!``(`f`,` `Fraction``::`from_str`(``"`1/2`"``)``.``unwrap``(``)``)``;` `//` parse a string
`//` Raw construct with no extra calculations.
`//` Most performant, but does not look for common denominator and may lead to unexpected results
`//` in following calculations. Only use if you are sure numerator/denominator are already normalized.
`assert_eq!``(`f`,` `Fraction``::`new_raw`(``1``u64``,` `2``u64``)``)``;`
`}`

Decimal:

`use` `std``::``str``::`FromStr`;`
`use` `fraction``::``{`Decimal`,` Fraction`}``;`
`fn` `main``(``)`` ``{`
`//` There are similar ways to construct Decimal. Underneath it is always represented as Fraction.
`//` When constructed, Decimal preserves its precision (number of digits after floating point).
`//` When two decimals are calculated, the result takes the biggest precision of both.
`//` The precision is used for visual representation (formatting and printing) and for comparison of two decimals.
`//` Precision is NOT used in any calculations. All calculations are lossless and implemented through Fraction.
`//` To override the precision use Decimal::set_precision.
`let` d `=` `Decimal``::`from`(``1``)``;` `//` from integer, precision = 0
`assert_eq!``(`d`,` `Decimal``::`from_fraction`(``Fraction``::`from`(``1``)``)``)``;` `//` from fraction, precision is calculated from fraction
`let` d `=` `Decimal``::`from`(``1.``3``)``;` `//` from float (f32, f64)
`assert_eq!``(`d`,` `Decimal``::`from_str`(``"`1.3`"``)``.``unwrap``(``)``)``;`
`let` d `=` `Decimal``::`from`(``0.``5``)``;` `//` from float (f32, f64)
`assert_eq!``(`d`,` `Decimal``::`from_str`(``"`1/2`"``)``.``unwrap``(``)``)``;`
`}`

## Format (convert to string)

Formatting works the same for both Decimal and Fraction (Decimal uses Fraction internally). The format implementation closely follows the rust Format trait documentation.

`type` `F` `=` `fraction``::`Fraction`;`
`let` result `=` `F``::`from`(``0.``7``)` `/` `0.``4``;`
`assert_eq!``(``format!``(``"``{}``"``,` result`)``,` `"`7/4`"``)``;`
`assert_eq!``(``format!``(``"``{:.2}``"``,` result`)``,` `"`1.75`"``)``;`
`assert_eq!``(``format!``(``"``{:#.3}``"``,` result`)``,` `"`1.750`"``)``;`

### Generic integer conversion

`use` `fraction``::``{`Sign`,` GenericFraction`}``;`
`type` `F` `=` `GenericFraction``<``u32``>``;`
`let` fra `=` `F``::`new_generic`(``Sign``::`Plus`,` `1``i8``,` `42``usize``)``.``unwrap``(``)``;`
`assert_eq!``(`fra`,` `F``::`new`(``1``u32``,` `42``u32``)``)``;`

### Postgres usage notes

It is recommended to use Decimal over Fraction for PostgreSQL interactions. When interacting with PostgreSQL, fraction type keeps the highest achievable precision up to 16383 digits after floating point. That may lead to suboptimal performance for such values as 1/3 or 1/7. Decimal has its own explicit precision, so there won't be accidental calculation of tens of thousands digits.

PostgreSQL uses i16 for its binary protocol, so you'll have to use at least u16 as the base type for your GenericFraction/GenericDecimal. However, it is also possible to workaround via DynaInt<u8, _something_more_than_u8_>.

It is recommended to use

so that by default you have on-stack math, and if necessary
heap memory gets allocated.`DynaInt <usize, BigUint>`

Otherwise, both types (fractions and decimals) should work transparently in accordance with Postgres crate documentation.

# Change Log

Look into the CHANGELOG.md file for details

#### Dependencies

~0.4–2.2MB

~51K SLoC