mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Add precision support for fixnums (#437)
- [ ] Changelog updated / no changelog update needed
This commit is contained in:
commit
a7269ed65f
|
@ -539,26 +539,55 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> Display for Num<I, N> {
|
||||||
//
|
//
|
||||||
// But if you think of a negative number, you'd like it to be `negative number - non negative fraction`
|
// But if you think of a negative number, you'd like it to be `negative number - non negative fraction`
|
||||||
// So we have to add 1 to the integral bit, and take 1 - fractional bit
|
// So we have to add 1 to the integral bit, and take 1 - fractional bit
|
||||||
if fractional != I::zero() && integral < I::zero() {
|
let sign = if fractional != I::zero() && integral < I::zero() {
|
||||||
integral = integral + I::one();
|
integral = integral + I::one();
|
||||||
if integral == I::zero() {
|
fractional = (I::one() << N) - fractional;
|
||||||
// If the number is in the range (-1, 0), then we just bumped `integral` from -1 to 0,
|
-1
|
||||||
// so we need to compensate for the missing negative sign.
|
} else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(precision) = f.precision() {
|
||||||
|
let precision_multiplier = I::from_as_i32(10_i32.pow(precision as u32));
|
||||||
|
|
||||||
|
let fractional_as_integer = fractional * precision_multiplier * I::ten();
|
||||||
|
let mut fractional_as_integer = fractional_as_integer >> N;
|
||||||
|
|
||||||
|
if fractional_as_integer % I::ten() >= I::from_as_i32(5) {
|
||||||
|
fractional_as_integer = fractional_as_integer + I::ten();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut fraction_to_write = fractional_as_integer / I::ten();
|
||||||
|
|
||||||
|
if fraction_to_write >= precision_multiplier {
|
||||||
|
integral = integral + I::from_as_i32(sign);
|
||||||
|
fraction_to_write = fraction_to_write - precision_multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
if sign == -1 && integral == I::zero() && fraction_to_write != I::zero() {
|
||||||
write!(f, "-")?;
|
write!(f, "-")?;
|
||||||
}
|
}
|
||||||
fractional = (I::one() << N) - fractional;
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(f, "{integral}")?;
|
write!(f, "{integral}")?;
|
||||||
|
|
||||||
if fractional != I::zero() {
|
if precision != 0 {
|
||||||
write!(f, ".")?;
|
write!(f, ".{:#0width$}", fraction_to_write, width = precision)?;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if sign == -1 && integral == I::zero() {
|
||||||
|
write!(f, "-")?;
|
||||||
|
}
|
||||||
|
write!(f, "{integral}")?;
|
||||||
|
|
||||||
while fractional & mask != I::zero() {
|
if fractional != I::zero() {
|
||||||
fractional = fractional * I::ten();
|
write!(f, ".")?;
|
||||||
write!(f, "{}", (fractional & !mask) >> N)?;
|
}
|
||||||
fractional = fractional & mask;
|
|
||||||
|
while fractional & mask != I::zero() {
|
||||||
|
fractional = fractional * I::ten();
|
||||||
|
write!(f, "{}", (fractional & !mask) >> N)?;
|
||||||
|
fractional = fractional & mask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1069,6 +1098,51 @@ mod tests {
|
||||||
assert_eq!(format!("{d}"), "-0.25");
|
assert_eq!(format!("{d}"), "-0.25");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod precision {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
macro_rules! num_ {
|
||||||
|
($n: literal) => {{
|
||||||
|
let a: Num<i32, 20> = num!($n);
|
||||||
|
a
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! test_precision {
|
||||||
|
($TestName: ident, $Number: literal, $Expected: literal) => {
|
||||||
|
test_precision! { $TestName, $Number, $Expected, 2 }
|
||||||
|
};
|
||||||
|
($TestName: ident, $Number: literal, $Expected: literal, $Digits: literal) => {
|
||||||
|
#[test]
|
||||||
|
fn $TestName() {
|
||||||
|
assert_eq!(
|
||||||
|
format!("{:.width$}", num_!($Number), width = $Digits),
|
||||||
|
$Expected
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test_precision!(positive_down, 1.2345678, "1.23");
|
||||||
|
test_precision!(positive_round_up, 1.237, "1.24");
|
||||||
|
test_precision!(negative_round_down, -1.237, "-1.24");
|
||||||
|
|
||||||
|
test_precision!(trailing_zero, 1.5, "1.50");
|
||||||
|
test_precision!(leading_zero, 1.05, "1.05");
|
||||||
|
|
||||||
|
test_precision!(positive_round_to_next_integer, 3.999, "4.00");
|
||||||
|
test_precision!(negative_round_to_next_integer, -3.999, "-4.00");
|
||||||
|
|
||||||
|
test_precision!(negative_round_to_1, -0.999, "-1.00");
|
||||||
|
test_precision!(positive_round_to_1, 0.999, "1.00");
|
||||||
|
|
||||||
|
test_precision!(positive_round_to_zero, 0.001, "0.00");
|
||||||
|
test_precision!(negative_round_to_zero, -0.001, "0.00");
|
||||||
|
|
||||||
|
test_precision!(zero_precision_negative, -0.001, "0", 0);
|
||||||
|
test_precision!(zero_precision_positive, 0.001, "0", 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sqrt() {
|
fn sqrt() {
|
||||||
for x in 1..1024 {
|
for x in 1..1024 {
|
||||||
|
|
Loading…
Reference in a new issue