The developpment of this package has been ceased, in favor of fpdec.rs.
Being based on const generics, this implementation of a fixed-point Decimal type provides some advantages:
Having the number of fractional digits as a constant type parameter provides the compiler with some extra opportunities to optimize the generated code. For example, in the implementation of the Add trait:
```
impl
where
PrecLimitCheck<{ P <= MAXPREC }>: True,
PrecLimitCheck<{ Q <= MAXPREC }>: True,
PrecLimitCheck<{ constmaxu8(P, Q) <= MAXPREC }>: True,
{
type Output = Decimal<{ constmax_u8(P, Q) }>; }
``` For each combination of P and Q the compiler can reduce the code for the
match statement to just one case. And the multiplication of two Decimals is reduced to the multiplication of two
integers (i128), because the resulting number of fractional digits is already
determined at compile time: ```
impl
where
PrecLimitCheck<{ P <= MAXPREC }>: True,
PrecLimitCheck<{ Q <= MAXPREC }>: True,
PrecLimitCheck<{ (constsumu8(P, Q)) <= MAXPREC }>: True,
{
type Output = Decimal<{ constsum_u8(P, Q) }>; }
``` But there are also some serious drawbacks:
Overall, the performance gains stemming from the use of const generics do not
outweigh the disadvantages. The package fpdec.rs follows the
same objectives as this package. It does not provides the same performance,
but avoids the drawbacks mentioned above. This crate strives to provide a fast implementation of 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 Experimental (work in progess) Add 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 The easiest method is to use the procedural macro ```rust let d = Dec!(-17.5);
asserteq!(d.tostring(), "-17.5");
``` Alternatively you can convert an integer, a float or a string to a ```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 ```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));
``` ```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 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");
```fn add(self, other: Decimal<Q>) -> Self::Output {
match P.cmp(&Q) {
Ordering::Equal => Self::Output {
coeff: Add::add(self.coeff, other.coeff),
},
Ordering::Greater => Self::Output {
coeff: Add::add(
self.coeff,
mul_pow_ten(other.coeff, P - Q),
),
},
Ordering::Less => Self::Output {
coeff: Add::add(
mul_pow_ten(self.coeff, Q - P),
other.coeff,
),
},
}
}
#[inline(always)]
fn mul(self, other: Decimal<Q>) -> Self::Output {
Self::Output {
coeff: self.coeff * other.coeff,
}
}
----------
Decimal
fixed-point
arithmetics.Objectives
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.Status
Getting started
rust-fixed-point-decimal
to your Cargo.toml
:toml
[dependencies]
rust-fixed-point-decimal = "0.1"
Note:
![allow(incomplete_features)]
![feature(genericconstexprs)]
Usage
Decimal
number can be created in different ways. Dec
:use rustfixedpoint_decimal::Dec;
Decimal
:use rustfixedpoint_decimal::Decimal;
#![allow(incomplete_features)]
#![feature(genericconstexprs)]
use rustfixedpoint_decimal::{Decimal, DecimalError};
use std::convert::TryFrom;
Ok::<(), DecimalError>(())
#![allow(incomplete_features)]
#![feature(genericconstexprs)]
use rustfixedpoint_decimal::{Decimal, ParseDecimalError};
use std::str::FromStr;
Ok::<(), ParseDecimalError>(())
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):#![allow(incomplete_features)]
#![feature(genericconstexprs)]
use rustfixedpoint_decimal::{Dec, Decimal};
Decimal
supports all five binary numerical operators +, -, *, /, and %, with
two Decimal
s or with a Decimal
and a basic integer (besides u128):#![allow(incomplete_features)]
#![feature(genericconstexprs)]
use rustfixedpoint_decimal::{Dec, Decimal};
#![allow(incomplete_features)]
#![feature(genericconstexprs)]
use rustfixedpoint_decimal::{Dec, Decimal};
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.#![allow(incomplete_features)]
#![feature(genericconstexprs)]
use rustfixedpoint_decimal::{Dec, Decimal, DivRounded, MulRounded};