From e78c9abcec512ec3c4409dc93826d145c7863e13 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sat, 5 Jun 2021 16:53:07 +0100 Subject: [PATCH 1/6] Add basic definition of rem and remassign --- agb/src/number.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/agb/src/number.rs b/agb/src/number.rs index 9590798a..c27401f9 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -1,6 +1,6 @@ use core::{ fmt::Display, - ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign}, }; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] @@ -96,6 +96,25 @@ where } } +impl Rem for Num +where + T: Into>, +{ + type Output = Self; + fn rem(self, modulus: T) -> Self::Output { + Num(self.0 % modulus.into().0) + } +} + +impl RemAssign for Num +where + T: Into>, +{ + fn rem_assign(&mut self, modulus: T) { + self.0 = (*self % modulus).0 + } +} + impl Neg for Num { type Output = Self; fn neg(self) -> Self::Output { @@ -107,6 +126,7 @@ impl Num { pub fn max() -> Self { Num(i32::MAX) } + pub fn min() -> Self { Num(i32::MIN) } From 8b2dfdffc1a795101477c7e082b4a234ca324a79 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sat, 5 Jun 2021 17:22:23 +0100 Subject: [PATCH 2/6] Add proper implementation of debug for Num --- agb/src/number.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/agb/src/number.rs b/agb/src/number.rs index c27401f9..c09b60f7 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -1,9 +1,9 @@ use core::{ - fmt::Display, + fmt::{Debug, Display}, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign}, }; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Num(i32); pub fn change_base(num: Num) -> Num { @@ -223,3 +223,9 @@ impl Display for Num { Ok(()) } } + +impl Debug for Num { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self) + } +} From 8b1ad400a70e37f3cdc11fef718ea03dde065854 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sat, 5 Jun 2021 17:23:06 +0100 Subject: [PATCH 3/6] Include fix length in debug string --- agb/src/number.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agb/src/number.rs b/agb/src/number.rs index c09b60f7..9be14ef4 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -226,6 +226,6 @@ impl Display for Num { impl Debug for Num { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self) + write!(f, "Num<{}>({})", N, self) } } From 56cf16def465553508835b23bc1f04abe784c618 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sat, 5 Jun 2021 17:23:28 +0100 Subject: [PATCH 4/6] Fix int() method to return as-if this was a float --- agb/src/number.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/agb/src/number.rs b/agb/src/number.rs index 9be14ef4..e63e8664 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -132,7 +132,14 @@ impl Num { } pub fn int(&self) -> i32 { - self.0 >> N + let fractional_part = self.0 & ((1 << N) - 1); + let self_as_int = self.0 >> N; + + if self_as_int < 0 && fractional_part != 0 { + self_as_int + 1 + } else { + self_as_int + } } pub fn new(integral: i32) -> Self { From cdaef51d76b8d96a191d75612d5d6bcb293823ab Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sat, 5 Jun 2021 17:23:43 +0100 Subject: [PATCH 5/6] Add tests for % --- agb/src/number.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/agb/src/number.rs b/agb/src/number.rs index e63e8664..34180c37 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -210,6 +210,46 @@ fn test_change_base(_gba: &mut super::Gba) { assert_eq!(three + change_base(two), 5.into()); } +#[test_case] +fn test_rem_returns_sensible_values_for_integers(_gba: &mut super::Gba) { + for i in -50..50 { + for j in -50..50 { + if j == 0 { + continue; + } + + let i_rem_j_normally = i % j; + let i_fixnum: Num<8> = i.into(); + + assert_eq!(i_fixnum % j, i_rem_j_normally.into()); + } + } +} + +#[test_case] +fn test_rem_returns_sensible_values_for_non_integers(_gba: &mut super::Gba) { + let one: Num<8> = 1.into(); + let third = one / 3; + + for i in -50..50 { + for j in -50..50 { + if j == 0 { + continue; + } + + // full calculation in the normal way + let x: Num<8> = third + i; + let y: Num<8> = j.into(); + + let truncated_division: Num<8> = (x / y).int().into(); + + let remainder = x - truncated_division * y; + + assert_eq!(x % y, remainder); + } + } +} + impl Display for Num { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let integral = self.0 >> N; From 363a16ce331192244c1d0f008cd2083988cf26c8 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sat, 5 Jun 2021 17:27:00 +0100 Subject: [PATCH 6/6] Add implementation of rem_euclid stolen from f32's implementation and add a test --- agb/src/number.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/agb/src/number.rs b/agb/src/number.rs index 34180c37..632d5ee2 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -142,6 +142,19 @@ impl Num { } } + pub fn rem_euclid(&self, rhs: Self) -> Self { + let r = *self % rhs; + if r < 0.into() { + if rhs < 0.into() { + r - rhs + } else { + r + rhs + } + } else { + r + } + } + pub fn new(integral: i32) -> Self { Self(integral << N) } @@ -250,6 +263,31 @@ fn test_rem_returns_sensible_values_for_non_integers(_gba: &mut super::Gba) { } } +#[test_case] +fn test_rem_euclid_is_always_positive_and_sensible(_gba: &mut super::Gba) { + let one: Num<8> = 1.into(); + let third = one / 3; + + for i in -50..50 { + for j in -50..50 { + if j == 0 { + continue; + } + + // full calculation in the normal way + let x: Num<8> = third + i; + let y: Num<8> = j.into(); + + let truncated_division: Num<8> = (x / y).int().into(); + + let remainder = x - truncated_division * y; + + let rem_euclid = x.rem_euclid(y); + assert!(rem_euclid > 0.into()); + } + } +} + impl Display for Num { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let integral = self.0 >> N;