forked from nonsensical-dev/zenyx-engine
335 lines
8.4 KiB
Rust
335 lines
8.4 KiB
Rust
|
use std::{
|
||
|
cmp::Ordering,
|
||
|
convert::From,
|
||
|
fmt,
|
||
|
hash::{Hash, Hasher},
|
||
|
ops::{
|
||
|
Add, AddAssign, BitAnd, BitOr, BitXor, Deref, DerefMut, Div, DivAssign, Mul, MulAssign,
|
||
|
Rem, RemAssign, Shl, Shr, Sub, SubAssign,
|
||
|
},
|
||
|
str::FromStr,
|
||
|
};
|
||
|
|
||
|
#[derive(Debug, Clone, Copy)]
|
||
|
pub struct BigInt<const N: usize> {
|
||
|
bytes: [u8; N],
|
||
|
len: usize,
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> BigInt<N> {
|
||
|
pub fn from_bytes(bytes: &[u8]) -> Self {
|
||
|
debug_assert!(bytes.len() != 0);
|
||
|
let mut len = bytes.len();
|
||
|
while len > 1 && bytes[len - 1] == 0 {
|
||
|
len -= 1;
|
||
|
}
|
||
|
let mut arr = [0u8; N];
|
||
|
arr[..len].copy_from_slice(&bytes[..len]);
|
||
|
BigInt { bytes: arr, len }
|
||
|
}
|
||
|
|
||
|
pub fn from_u64(value: u64) -> Self {
|
||
|
Self::from_bytes(&value.to_le_bytes())
|
||
|
}
|
||
|
|
||
|
fn trim_zeros(mut self) -> Self {
|
||
|
while self.len > 1 && self.bytes[self.len - 1] == 0 {
|
||
|
self.len -= 1;
|
||
|
}
|
||
|
self
|
||
|
}
|
||
|
|
||
|
pub fn max_value() -> Self {
|
||
|
let mut arr = [0u8; N];
|
||
|
arr.fill(255);
|
||
|
BigInt { bytes: arr, len: N }
|
||
|
}
|
||
|
pub fn div_rem(&self, other: &Self) -> (Self, Self) {
|
||
|
let mut quotient = BigInt::from(0);
|
||
|
let mut remainder = self.clone();
|
||
|
let divisor = other.clone();
|
||
|
|
||
|
while remainder >= divisor {
|
||
|
let mut multiple = divisor.clone();
|
||
|
let mut temp_quotient = BigInt::from(1);
|
||
|
while multiple + multiple <= remainder {
|
||
|
multiple = multiple + multiple;
|
||
|
temp_quotient = temp_quotient + temp_quotient;
|
||
|
}
|
||
|
remainder = remainder - multiple;
|
||
|
quotient = quotient + temp_quotient;
|
||
|
}
|
||
|
(quotient.trim_zeros(), remainder.trim_zeros())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> Add for BigInt<N> {
|
||
|
type Output = Self;
|
||
|
fn add(self, rhs: Self) -> Self {
|
||
|
let mut result = [0u8; N];
|
||
|
let mut carry = 0u16;
|
||
|
let max_len = self.len.max(rhs.len);
|
||
|
let mut res_len = 0;
|
||
|
|
||
|
for i in 0..max_len {
|
||
|
let a = self.bytes.get(i).copied().unwrap_or(0) as u16;
|
||
|
let b = rhs.bytes.get(i).copied().unwrap_or(0) as u16;
|
||
|
let sum = a + b + carry;
|
||
|
result[i] = (sum % 256) as u8;
|
||
|
carry = sum / 256;
|
||
|
res_len = i + 1;
|
||
|
}
|
||
|
|
||
|
if carry > 0 {
|
||
|
result[res_len] = carry as u8;
|
||
|
res_len += 1;
|
||
|
}
|
||
|
|
||
|
BigInt {
|
||
|
bytes: result,
|
||
|
len: res_len,
|
||
|
}
|
||
|
.trim_zeros()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> AddAssign for BigInt<N> {
|
||
|
fn add_assign(&mut self, rhs: Self) {
|
||
|
*self = *self + rhs;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> Sub for BigInt<N> {
|
||
|
type Output = Self;
|
||
|
fn sub(self, rhs: Self) -> Self {
|
||
|
let mut result = [0u8; N];
|
||
|
let mut borrow = 0i16;
|
||
|
let mut res_len = 0;
|
||
|
|
||
|
for i in 0..self.len {
|
||
|
let a = self.bytes[i] as i16;
|
||
|
let b = rhs.bytes.get(i).copied().unwrap_or(0) as i16;
|
||
|
let mut diff = a - b - borrow;
|
||
|
borrow = 0;
|
||
|
|
||
|
if diff < 0 {
|
||
|
diff += 256;
|
||
|
borrow = 1;
|
||
|
}
|
||
|
|
||
|
result[i] = diff as u8;
|
||
|
res_len = i + 1;
|
||
|
}
|
||
|
|
||
|
BigInt {
|
||
|
bytes: result,
|
||
|
len: res_len,
|
||
|
}
|
||
|
.trim_zeros()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> SubAssign for BigInt<N> {
|
||
|
fn sub_assign(&mut self, rhs: Self) {
|
||
|
*self = *self - rhs;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> Mul for BigInt<N> {
|
||
|
type Output = Self;
|
||
|
fn mul(self, rhs: Self) -> Self {
|
||
|
let mut result = BigInt {
|
||
|
bytes: [0; N],
|
||
|
len: 0,
|
||
|
};
|
||
|
|
||
|
for i in 0..self.len {
|
||
|
let mut carry = 0u16;
|
||
|
for j in 0..rhs.len {
|
||
|
let idx = i + j;
|
||
|
if idx >= N {
|
||
|
panic!("Multiplication overflow");
|
||
|
}
|
||
|
let product =
|
||
|
self.bytes[i] as u16 * rhs.bytes[j] as u16 + carry + result.bytes[idx] as u16;
|
||
|
result.bytes[idx] = (product % 256) as u8;
|
||
|
carry = product / 256;
|
||
|
}
|
||
|
let mut k = i + rhs.len;
|
||
|
while carry > 0 && k < N {
|
||
|
let sum = result.bytes[k] as u16 + carry;
|
||
|
result.bytes[k] = (sum % 256) as u8;
|
||
|
carry = sum / 256;
|
||
|
k += 1;
|
||
|
}
|
||
|
result.len = result.len.max(k);
|
||
|
}
|
||
|
|
||
|
result.trim_zeros()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> MulAssign for BigInt<N> {
|
||
|
fn mul_assign(&mut self, rhs: Self) {
|
||
|
*self = *self * rhs;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> Div for BigInt<N> {
|
||
|
type Output = Self;
|
||
|
fn div(self, rhs: Self) -> Self {
|
||
|
self.div_rem(&rhs).0
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> DivAssign for BigInt<N> {
|
||
|
fn div_assign(&mut self, rhs: Self) {
|
||
|
*self = *self / rhs;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> Rem for BigInt<N> {
|
||
|
type Output = Self;
|
||
|
fn rem(self, rhs: Self) -> Self {
|
||
|
self.div_rem(&rhs).1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> RemAssign for BigInt<N> {
|
||
|
fn rem_assign(&mut self, rhs: Self) {
|
||
|
*self = *self % rhs;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> PartialEq for BigInt<N> {
|
||
|
fn eq(&self, other: &Self) -> bool {
|
||
|
self.bytes[..self.len] == other.bytes[..other.len]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> Eq for BigInt<N> {}
|
||
|
|
||
|
impl<const N: usize> Hash for BigInt<N> {
|
||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||
|
self.bytes[..self.len].hash(state);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> PartialOrd for BigInt<N> {
|
||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||
|
Some(self.cmp(other))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> Ord for BigInt<N> {
|
||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||
|
if self.len != other.len {
|
||
|
return self.len.cmp(&other.len);
|
||
|
}
|
||
|
for i in (0..self.len).rev() {
|
||
|
match self.bytes[i].cmp(&other.bytes[i]) {
|
||
|
Ordering::Equal => continue,
|
||
|
ord => return ord,
|
||
|
}
|
||
|
}
|
||
|
Ordering::Equal
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> Deref for BigInt<N> {
|
||
|
type Target = [u8];
|
||
|
fn deref(&self) -> &[u8] {
|
||
|
&self.bytes[..self.len]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> DerefMut for BigInt<N> {
|
||
|
fn deref_mut(&mut self) -> &mut [u8] {
|
||
|
&mut self.bytes[..self.len]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
macro_rules! impl_from_int {
|
||
|
($($t:ty),*) => {$(
|
||
|
impl<const N: usize> From<$t> for BigInt<N> {
|
||
|
fn from(value: $t) -> Self {
|
||
|
let bytes = value.to_le_bytes();
|
||
|
Self::from_bytes(&bytes)
|
||
|
}
|
||
|
}
|
||
|
)*};
|
||
|
}
|
||
|
|
||
|
impl_from_int!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
|
||
|
|
||
|
impl<const N: usize> FromStr for BigInt<N> {
|
||
|
type Err = &'static str;
|
||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||
|
let mut result = BigInt::from(0u8);
|
||
|
for c in s.chars() {
|
||
|
if !c.is_digit(10) {
|
||
|
return Err("Invalid digit");
|
||
|
}
|
||
|
let digit = c.to_digit(10).unwrap() as u8;
|
||
|
result = result * BigInt::from(10u8) + BigInt::from(digit);
|
||
|
}
|
||
|
Ok(result)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<const N: usize> fmt::Display for BigInt<N> {
|
||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||
|
if self.len == 0 {
|
||
|
return write!(f, "0");
|
||
|
}
|
||
|
let mut digits = Vec::new();
|
||
|
let mut bytes = self.bytes[..self.len].to_vec();
|
||
|
|
||
|
while !bytes.is_empty() {
|
||
|
let mut remainder = 0u16;
|
||
|
for byte in bytes.iter_mut().rev() {
|
||
|
let value = *byte as u16 + remainder * 256;
|
||
|
*byte = (value / 10) as u8;
|
||
|
remainder = value % 10;
|
||
|
}
|
||
|
digits.push(remainder as u8);
|
||
|
while !bytes.is_empty() && bytes[bytes.len() - 1] == 0 {
|
||
|
bytes.pop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
digits.reverse();
|
||
|
let s = digits
|
||
|
.iter()
|
||
|
.map(|d| char::from_digit(*d as u32, 10).unwrap())
|
||
|
.collect::<String>();
|
||
|
write!(f, "{}", s)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
||
|
struct Dint {
|
||
|
bytes: Vec<u8>,
|
||
|
}
|
||
|
|
||
|
impl Deref for Dint {
|
||
|
type Target = [u8];
|
||
|
fn deref(&self) -> &[u8] {
|
||
|
&self.bytes
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl DerefMut for Dint {
|
||
|
fn deref_mut(&mut self) -> &mut [u8] {
|
||
|
&mut self.bytes
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn main() {
|
||
|
type TheInt = BigInt<2>;
|
||
|
let mut test: TheInt = TheInt::max_value();
|
||
|
let thing = BigInt::<9>::max_value();
|
||
|
test /= 2.into();
|
||
|
println!("{test}")
|
||
|
}
|