This crate strives to provide a fast implementation of Decimal
fixed-point
arithmetics.
It is targeted at typical business applications, dealing with numbers representing quantities, money and the like, not at scientific computations, for which the accuracy of floating point math is - in most cases - sufficient.
At the binary level a Decimal number is represented as a coefficient (stored
as an i128
value) combined with a type parameter specifying the number of
fractional decimal digits. I. e., the whole implementation is based on "const
generics" and needs a rust version supporting this feature.
Experimental (work in progess)
Add rust-fixed-point-decimal
to your Cargo.toml
:
toml
[dependencies]
rust-fixed-point-decimal = "0.1"
Because the implementation of "const generics" is still incomplete, you have to put the following at the start of your main.rs or lib.rs file:
```rust
```
A Decimal
number can be created in different ways.
The easiest method is to use the procedural macro Dec
:
```rust
let d = Dec!(-17.5); asserteq!(d.tostring(), "-17.5"); ```
Alternatively you can convert an integer, a float or a string to a Decimal
:
```rust
let d = Decimal::<2>::from(297i32); asserteq!(d.to_string(), "297.00"); ```
```rust
let d = Decimal::<5>::tryfrom(83.0025)?; asserteq!(d.to_string(), "83.00250");
```
```rust
let d = Decimal::<4>::fromstr("38.207")?; asserteq!(d.to_string(), "38.2070");
```
The sign of a Decimal
can be inverted using the unary minus operator and a
Decimal
instance can be compared to other instances of type Decimal
or all
basic types of integers (besides u128 and atm besides u8, which causes a
compiler error):
```rust
let x = Dec!(129.24); let y = -x; asserteq!(y.tostring(), "-129.24"); assert!(-129i64 > y); let z = -y; asserteq!(x, z); let z = Dec!(0.00097); assert!(x > z); assert!(y <= z); assert!(z != 7u32); assert!(7u32 == Dec!(7.00)); ```
Decimal
supports all five binary numerical operators +, -, *, /, and %, with
two Decimal
s or with a Decimal
and a basic integer (besides u128):
```rust
let x = Dec!(17.5); let y = Dec!(6.40); let z = x + y; asserteq!(z.tostring(), "23.90"); let z = x - y; asserteq!(z.tostring(), "11.10"); let z = x * y; asserteq!(z.tostring(), "112.000"); let z = x / y; asserteq!(z.tostring(), "2.734375000"); let z = x % y; asserteq!(z.tostring(), "4.70"); ```
```rust
let x = Dec!(17.5); let y = -5i64; let z = x + y; asserteq!(z.tostring(), "12.5"); let z = x - y; asserteq!(z.tostring(), "22.5"); let z = y * x; asserteq!(z.tostring(), "-87.5"); let z = x / y; asserteq!(z.tostring(), "-3.500000000"); let z = x % y; asserteq!(z.to_string(), "2.5"); ```
All these binary numeric operators panic if the result is not representable as
a Decimal
according to the constraints stated above. In addition there are
functions implementing "checked" variants of the operators which return
Option::None
instead of panicking.
For Multiplication and Division there are also functions which return a result rounded to a number of fractional digits determined by the target type:
```rust
let x = Dec!(17.5); let y = Dec!(6.47); let z: Decimal<1> = x.mulrounded(y); asserteq!(z.tostring(), "113.2"); let z: Decimal<3> = x.divrounded(y); asserteq!(z.tostring(), "2.705"); ```