grass/src/value/number.rs

243 lines
5.2 KiB
Rust
Raw Normal View History

2020-02-08 18:43:18 -05:00
use std::convert::From;
use std::fmt::{self, Display, Write};
2020-02-16 11:59:04 -05:00
use std::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
};
2020-02-08 18:43:18 -05:00
use num_bigint::BigInt;
use num_rational::BigRational;
2020-02-14 12:30:48 -05:00
use num_traits::sign::Signed;
2020-02-08 18:43:18 -05:00
const PRECISION: usize = 10;
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) struct Number {
val: BigRational,
}
impl Number {
pub const fn new(val: BigRational) -> Number {
Number { val }
}
pub fn to_integer(&self) -> BigInt {
self.val.to_integer()
}
pub fn ratio<A: Into<BigInt>, B: Into<BigInt>>(a: A, b: B) -> Self {
Number::new(BigRational::new(a.into(), b.into()))
}
pub fn round(self) -> Self {
Number {
val: self.val.round(),
}
}
pub fn ceil(self) -> Self {
Number {
val: self.val.ceil(),
}
}
pub fn floor(self) -> Self {
Number {
val: self.val.floor(),
}
}
2020-02-14 12:30:48 -05:00
pub fn abs(self) -> Self {
Number {
val: self.val.abs(),
}
}
pub fn is_decimal(&self) -> bool {
self.val.denom() != &BigInt::from(1)
}
}
impl fmt::LowerHex for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:0>2x}", self.val.to_integer())
}
2020-02-08 18:43:18 -05:00
}
impl From<BigInt> for Number {
fn from(b: BigInt) -> Self {
Number {
val: BigRational::from_integer(b),
}
}
}
impl From<Number> for BigInt {
2020-02-14 18:28:09 -05:00
#[inline]
fn from(b: Number) -> Self {
b.to_integer()
}
}
macro_rules! from_integer {
($ty:ty) => {
impl From<$ty> for Number {
fn from(b: $ty) -> Self {
Number {
val: BigRational::from_integer(BigInt::from(b)),
}
}
}
};
}
impl From<f64> for Number {
fn from(b: f64) -> Self {
Number {
val: BigRational::from_float(b).unwrap(),
}
}
}
from_integer!(u16);
from_integer!(usize);
from_integer!(i32);
from_integer!(u8);
2020-02-08 18:43:18 -05:00
impl Display for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2020-02-16 15:20:38 -05:00
if self.val.is_negative() {
f.write_char('-')?;
}
2020-03-17 12:47:27 -04:00
let mut whole = self.val.to_integer().abs();
let mut dec = String::new();
2020-02-08 18:43:18 -05:00
let mut frac = self.val.fract();
if frac != BigRational::from_integer(BigInt::from(0)) {
2020-03-17 12:47:27 -04:00
dec.write_char('.')?;
for _ in 0..(PRECISION - 1) {
2020-02-08 18:43:18 -05:00
frac *= BigRational::from_integer(BigInt::from(10));
2020-03-17 12:47:27 -04:00
write!(dec, "{}", frac.to_integer().abs())?;
2020-02-08 18:43:18 -05:00
frac = frac.fract();
if frac == BigRational::from_integer(BigInt::from(0)) {
break;
}
}
2020-02-08 18:51:29 -05:00
if frac != BigRational::from_integer(BigInt::from(0)) {
2020-03-17 12:47:27 -04:00
let f = (frac * BigRational::from_integer(BigInt::from(10)))
.round()
.abs()
.to_integer();
if f == BigInt::from(10) {
loop {
match dec.pop().unwrap() {
'9' => continue,
'.' => {
whole += 1;
break;
}
c => {
dec.push_str(&(c.to_digit(10).unwrap() + 1).to_string());
break;
}
}
}
} else {
write!(dec, "{}", f)?;
}
2020-02-08 18:51:29 -05:00
}
2020-02-08 18:43:18 -05:00
}
2020-03-17 12:47:27 -04:00
write!(f, "{}", whole)?;
write!(f, "{}", dec)?;
2020-02-08 18:43:18 -05:00
Ok(())
}
}
impl Add for Number {
type Output = Self;
fn add(self, other: Self) -> Self {
Number {
val: self.val + other.val,
}
}
}
impl AddAssign for Number {
fn add_assign(&mut self, other: Self) {
self.val += other.val
}
}
2020-02-08 18:43:18 -05:00
impl Sub for Number {
type Output = Self;
fn sub(self, other: Self) -> Self {
Number {
val: self.val - other.val,
}
}
}
impl SubAssign for Number {
fn sub_assign(&mut self, other: Self) {
self.val -= other.val
}
}
impl Mul for Number {
type Output = Self;
fn mul(self, other: Self) -> Self {
Number {
val: self.val * other.val,
}
}
}
impl MulAssign for Number {
fn mul_assign(&mut self, other: Self) {
self.val *= other.val
}
}
impl Div for Number {
type Output = Self;
fn div(self, other: Self) -> Self {
Number {
val: self.val / other.val,
}
}
}
impl DivAssign for Number {
fn div_assign(&mut self, other: Self) {
self.val /= other.val
}
}
2020-02-14 09:44:46 -05:00
impl Rem for Number {
type Output = Self;
fn rem(self, other: Self) -> Self {
Number {
val: self.val % other.val,
}
}
}
impl RemAssign for Number {
fn rem_assign(&mut self, other: Self) {
self.val %= other.val
}
}
impl Neg for Number {
type Output = Self;
fn neg(self) -> Self {
2020-02-16 11:59:04 -05:00
Number { val: -self.val }
}
2020-02-16 11:59:04 -05:00
}