Looking for code review for my simple Rust big integer

Previously, I have write a question here Simple Rust BigInt and I think i have to make it myself. I made it to fit to online grader like this.

So far, I only have implement the addition and subtraction. Before I’m going too far and the code become more complicated, I have to make sure that I’m not doing anything wrong. I need some advice regarding my code.

Thanks in advance.

// # BigInteger

// Don't change the base
const BASE: i32 = 1000;

#[derive(Clone, Debug)]
struct BigInteger {
    // Sign are used to determine wether the number is positive or negative
    // * true for positive
    // * false for negative
    sign: bool,
    number: Vec<i32>,
}

impl BigInteger {
    // You can use this to convert a String to BigInteger type
    fn new(number_string: String) -> BigInteger {
        let mut number_string = number_string;
        // check if it's a negative value or not by it's sign
        let sign = number_string.chars().nth(0).unwrap() != '-';
        // removing the sign if it exist
        if !sign || number_string.chars().nth(0).unwrap() == '+' {
            number_string.remove(0);
        }
        BigInteger {
            sign,
            number: BigUInteger::new(number_string).number,
        }
    }
}

// Substraction for BigInteger
impl std::ops::Sub for BigInteger {
    type Output = BigInteger;

    fn sub(self, other: BigInteger) -> BigInteger {
        let mut other = BigInteger { ..other };
        let mut self_ = BigInteger { ..self };
        // To make the bigger number goes to left (self_) and the smaller goes to right (other)
        let swapped = if BigUInteger::from_BigInteger(self_.clone())
            < BigUInteger::from_BigInteger(other.clone())
        {
            std::mem::swap(&mut self_, &mut other);
            true
        } else {
            false
        };
        // (1+) - (2+)
        if self_.sign && other.sign {
            BigInteger {
                sign: !swapped,
                number: (BigUInteger::from_BigInteger(self_.clone())
                    - BigUInteger::from_BigInteger(other.clone()))
                .number,
            }
        // (1-) - (2-) == -((1+) - (2+))
        } else if !self_.sign && !other.sign {
            BigInteger {
                sign: swapped,
                number: (BigUInteger::from_BigInteger(self_.clone())
                    - BigUInteger::from_BigInteger(other.clone()))
                .number,
            }
        // (1-) - (2+) == -((1+) + (2+))
        } else if !self_.sign && other.sign {
            BigInteger {
                sign: swapped,
                number: (BigUInteger::from_BigInteger(self_.clone())
                    + BigUInteger::from_BigInteger(other.clone()))
                .number,
            }
        // (1+) - (2-) == (1+) + (2+)
        } else {
            BigInteger {
                sign: !swapped,
                number: (BigUInteger::from_BigInteger(self_.clone())
                    + BigUInteger::from_BigInteger(other.clone()))
                .number,
            }
        }
    }
}

// Addition for BigInteger
impl std::ops::Add for BigInteger {
    type Output = BigInteger;

    fn add(self, other: BigInteger) -> BigInteger {
        let mut other = BigInteger { ..other };
        let mut self_ = BigInteger { ..self };
        // (1+) + (2+)
        if self_.sign == other.sign {
            BigInteger {
                sign: self_.sign,
                number: (BigUInteger::from_BigInteger(self_.clone())
                    + BigUInteger::from_BigInteger(other.clone()))
                .number,
            }
        } else {
            // To make the bigger number goes to left (self_) and the smaller goes to right (other)
            if BigUInteger::from_BigInteger(self_.clone())
                < BigUInteger::from_BigInteger(other.clone())
            {
                std::mem::swap(&mut self_, &mut other);
            }
            // (1+) +  (2-) == (1+) - (2+)
            if self_.sign && !other.sign {
                BigInteger {
                    sign: true,
                    number: (BigUInteger::from_BigInteger(self_.clone())
                        - BigUInteger::from_BigInteger(other.clone()))
                    .number,
                }
            // (1-) + (2+) == -((1+) - (2+))
            } else {
                BigInteger {
                    sign: false,
                    number: (BigUInteger::from_BigInteger(self_.clone())
                        - BigUInteger::from_BigInteger(other.clone()))
                    .number,
                }
            }
        }
    }
}

impl std::cmp::Eq for BigInteger {}

impl std::cmp::PartialEq for BigInteger {
    fn eq(&self, other: &BigInteger) -> bool {
        self.sign == other.sign
            && BigUInteger::from_BigInteger(self.clone())
                == BigUInteger::from_BigInteger(other.clone())
    }
}

impl std::cmp::Ord for BigInteger {
    fn cmp(&self, other: &BigInteger) -> std::cmp::Ordering {
        if self.sign != other.sign {
            if !self.sign {
                std::cmp::Ordering::Less
            } else {
                std::cmp::Ordering::Greater
            }
        } else {
            if self.sign {
                BigUInteger::from_BigInteger(self.clone())
                    .cmp(&BigUInteger::from_BigInteger(other.clone()))
            } else {
                BigUInteger::from_BigInteger(other.clone())
                    .cmp(&BigUInteger::from_BigInteger(self.clone()))
            }
        }
    }
}

impl std::cmp::PartialOrd for BigInteger {
    fn partial_cmp(&self, other: &BigInteger) -> std::option::Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl std::fmt::Display for BigInteger {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        if self.number.iter().all(|&x| x == 0) {
            write!(f, "{}", "0")
        } else if self.sign {
            write!(
                f,
                "{}",
                BigUInteger::from_BigInteger(self.clone()).to_string()
            )
        } else {
            write!(
                f,
                "-{}",
                BigUInteger::from_BigInteger(self.clone()).to_string()
            )
        }
    }
}

// # BigUInteger (Big Unsigned Integer)

#[derive(Clone, Debug)]
struct BigUInteger {
    number: Vec<i32>,
}

impl BigUInteger {
    fn new(number_string: String) -> BigUInteger {
        let mut number_string = number_string;
        if number_string.chars().nth(0).unwrap() == '-'
            || number_string.chars().nth(0).unwrap() == '+'
        {
            number_string.remove(0);
        }
        let mut number_vector: Vec<i32> = Vec::new();
        let base_dig = f64::from(BASE).log10() as usize;
        // Backward version compatibility, most of online judger doesn't support step_by yet
        // - .step_by(base_dig)
        // + .filter(|x| (number_string.len() - x) % base_dig == 0)
        for i in (base_dig..number_string.len() + 1)
            .rev()
            .filter(|x| (number_string.len() - x) % base_dig == 0)
        {
            let temp = &number_string[i - base_dig..i]
                .parse::<i32>()
                .unwrap()
                .clone();
            number_vector.push(*temp);
        }
        if number_string.len() % base_dig != 0 {
            let temp = &number_string[0..number_string.len() % base_dig]
                .parse::<i32>()
                .unwrap();
            number_vector.push(*temp);
        }
        BigUInteger {
            number: number_vector.iter().rev().cloned().collect::<Vec<i32>>(),
        }
    }

    // dropping the sign
    #[allow(non_snake_case)]
    fn from_BigInteger(big_integer: BigInteger) -> BigUInteger {
        BigUInteger {
            number: big_integer.number,
        }
    }

    fn to_string(&self) -> String {
        let mut output_string: String = self
            .number
            .iter()
            .map(|&x| format!("{:03}", x))
            .collect::<Vec<String>>()
            .join("");
        while &output_string[0..1] == "0" && output_string.len() > 1 {
            output_string.remove(0);
        }
        output_string
    }
}

impl std::ops::Sub for BigUInteger {
    type Output = BigUInteger;

    fn sub(self, other: BigUInteger) -> BigUInteger {
        // Implemented from: https://www.geeksforgeeks.org/difference-of-two-large-numbers/
        let mut other = BigUInteger { ..other };
        let mut self_ = BigUInteger { ..self };
        if self_.number.len() < other.number.len() {
            std::mem::swap(&mut self_, &mut other);
        }
        let mut number_output: Vec<i32> = Vec::new();
        let digit_difference = self_.number.len() - other.number.len();
        let mut carry: i32 = 0;
        for i in (0..other.number.len()).rev() {
            let mut sub: i32 = self_.number[i + digit_difference] - other.number[i] - carry;
            if sub < 0 {
                sub += BASE;
                carry = 1;
            } else {
                carry = 0;
            }
            number_output.push(sub);
        }
        for i in (0..self_.number.len() - other.number.len()).rev() {
            if self_.number[i] == 0 && carry != 0 {
                number_output.push(BASE - 1);
                continue;
            }
            let sub = self_.number[i] - carry;
            if i > 0 || sub > 0 {
                number_output.push(sub);
            }
            carry = 0;
        }
        BigUInteger {
            number: number_output.iter().rev().cloned().collect::<Vec<i32>>(),
        }
    }
}

impl std::ops::Add for BigUInteger {
    type Output = BigUInteger;

    fn add(self, other: BigUInteger) -> BigUInteger {
        // Implemented from https://www.geeksforgeeks.org/sum-two-large-numbers/
        let mut other = BigUInteger { ..other };
        let mut self_ = BigUInteger { ..self };
        if self_.number.len() > other.number.len() {
            std::mem::swap(&mut self_, &mut other);
        }
        let mut number_output: Vec<i32> = Vec::new();
        let digit_difference = other.number.len() - self_.number.len();
        let mut carry: i32 = 0;
        for i in (0..self_.number.len()).rev() {
            let sum = self_.number[i] + other.number[i + digit_difference] + carry;
            number_output.push(sum % BASE);
            carry = sum / BASE;
        }
        for i in (0..other.number.len() - self_.number.len()).rev() {
            let sum = other.number[i] + carry;
            number_output.push(sum % BASE);
            carry = sum / BASE;
        }
        if carry != 0 {
            number_output.push(carry);
        }
        BigUInteger {
            number: number_output.iter().rev().cloned().collect::<Vec<i32>>(),
        }
    }
}

impl std::cmp::Eq for BigUInteger {}

impl std::cmp::PartialEq for BigUInteger {
    fn eq(&self, other: &BigUInteger) -> bool {
        self.number == other.number
    }
}

impl std::cmp::Ord for BigUInteger {
    fn cmp(&self, other: &BigUInteger) -> std::cmp::Ordering {
        if self.number.len() < other.number.len() {
            std::cmp::Ordering::Less
        } else if self.number.len() > other.number.len() {
            std::cmp::Ordering::Greater
        } else {
            for (self_i, other_i) in self.number.iter().zip(&other.number) {
                if self_i < other_i {
                    return std::cmp::Ordering::Less;
                } else if self_i > other_i {
                    return std::cmp::Ordering::Greater;
                }
            }
            std::cmp::Ordering::Equal
        }
    }
}

impl std::cmp::PartialOrd for BigUInteger {
    fn partial_cmp(&self, other: &BigUInteger) -> std::option::Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl std::fmt::Display for BigUInteger {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

fn main() {
    let mut input: String = String::new();
    std::io::stdin().read_line(&mut input).ok();
    let num_l: Vec<String> = input
        .trim()
        .split_whitespace()
        .map(|x| x.to_string())
        .collect::<Vec<String>>();
    println!(
        "{} + {} = {}",
        BigInteger::new(num_l[0].clone()),
        BigInteger::new(num_l[1].clone()),
        BigInteger::new(num_l[0].clone()) + BigInteger::new(num_l[1].clone())
    );
    println!(
        "{} - {} = {}",
        BigInteger::new(num_l[0].clone()),
        BigInteger::new(num_l[1].clone()),
        BigInteger::new(num_l[0].clone()) - BigInteger::new(num_l[1].clone())
    );
}

Gist: https://gist.github.com/andraantariksa/56952107d7d431592481129603b7230c

Have you tried clippy? (psst, I don’t think so :slight_smile:)

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.