From 2aa53c41dc82328308b9e961f556205de5037735 Mon Sep 17 00:00:00 2001 From: Jack Jackson Date: Mon, 15 May 2023 21:18:04 -0700 Subject: [PATCH] First pass --- .gitignore | 1 + Cargo.lock | 7 +++ Cargo.toml | 8 +++ src/lib.rs | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e68b8a1 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "realNumbers" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..865bd62 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "realNumbers" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8be1352 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,167 @@ +use std::collections::HashMap; +use std::ops::{Add, Sub}; +use std::cmp::max; + +#[derive(Debug)] +struct Real { + int_part: i32, + decimal_parts: HashMap +} + +impl Real { + pub fn new_int(int_part: i32) -> Real { + Real { int_part: int_part, decimal_parts: HashMap::new() } + } + + pub fn new(int_part: i32, decimal_parts: HashMap) -> Real { + Real { int_part: int_part, decimal_parts: decimal_parts } + } + + pub fn from_string(s: &str) -> Real { + let first_period_index = s.find('.'); + dbg!(first_period_index); + match first_period_index { + None => { + Real { int_part: s.parse::().unwrap(), decimal_parts: HashMap::new() } + }, + Some(idx) => { + let int_part = s[0..idx].parse::().unwrap(); + dbg!(int_part); + let decimal_string = &s[idx+1..]; + dbg!(decimal_string); + + match decimal_string.find('.') { + Some(_) => { + panic!("Found two periods in input string"); + }, + None => { + let length = decimal_string.len(); + dbg!(length); + let mut decimal_parts = HashMap::new(); + for idx in 0..length { + let c = decimal_string.as_bytes()[idx] as char; + let num = c.to_digit(10).unwrap(); + if num != 0 { + decimal_parts.entry(idx as i32).or_insert(num as i8); + } + } + Real { int_part: int_part, decimal_parts: decimal_parts } + } + } + + } + } + } +} + +impl Add for Real { + type Output = Real; + + fn add(self, other: Real) -> Real { + let mut int_part = self.int_part + other.int_part; + let mut decimal_part = HashMap::new(); + let highest_index = max( + self.decimal_parts.keys().max().unwrap_or(&0), + other.decimal_parts.keys().max().unwrap_or(&0)); + let mut carry = false; + for idx in (0..=*highest_index).rev() { + let borrowed = &idx; + let sum = self.decimal_parts.get(borrowed).unwrap_or(&0) + other.decimal_parts.get(borrowed).unwrap_or(&0) + if carry {1} else {0}; + carry = sum > 9; + let units = sum % 10; + if units != 0 { + decimal_part.entry( *borrowed).or_insert(units); + } + } + if carry { + int_part += 1; + } + Real::new(int_part, decimal_part) + } +} + +impl Sub for Real { + type Output = Real; + + fn sub(self, other: Real) -> Real { + let int_part = self.int_part - other.int_part; + Real::new_int(int_part) + } +} + +impl PartialEq for Real { + fn eq(&self, other: &Real) -> bool { + // And also compare decimals + self.int_part == other.int_part && + self.decimal_parts == other.decimal_parts + } +} + + +#[cfg(test)] +mod tests { + use crate::Real; + + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + } + + #[test] + fn int_addition() { + let one = Real::new_int(1); + let two = Real::new_int(2); + assert_eq!(one + two, Real::new_int(3)); + } + + #[test] + fn real_addition() { + // Basic equality + assert_eq!( + Real::from_string("1.23") + Real::from_string("3.45"), + Real::from_string("4.68") + ); + + // Basic inequality + assert_ne!( + Real::from_string("1.23") + Real::from_string("3.45"), + Real::from_string("4.70") + ); + + // Carry + assert_eq!( + Real::from_string("0.09") + Real::from_string("0.01"), + Real::from_string("0.1") + ); + + // Multiple carry + assert_eq!( + Real::from_string("0.99") + Real::from_string("0.01"), + Real::from_string("1") + ); + + // Ignore trailing zeros + assert_eq!( + Real::from_string("1.00"), + Real::from_string("1") + ); + assert_eq!( + Real::from_string("2.00000"), + Real::from_string("2.00") + ); + assert_eq!( + Real::from_string("3.000"), + Real::new_int(3) + ); + + + } + + #[test] + fn subtraction() { + let three = Real::new_int(3); + let one = Real::new_int(1); + assert_eq!(three - one, Real::new_int(2)); + } +} \ No newline at end of file