|
| 1 | +/// Performs long multiplication on string representations of non-negative numbers. |
| 2 | +pub fn multiply(num1: &str, num2: &str) -> String { |
| 3 | + if !is_valid_nonnegative(num1) || !is_valid_nonnegative(num2) { |
| 4 | + panic!("String does not conform to specification") |
| 5 | + } |
| 6 | + |
| 7 | + if num1 == "0" || num2 == "0" { |
| 8 | + return "0".to_string(); |
| 9 | + } |
| 10 | + let output_size = num1.len() + num2.len(); |
| 11 | + |
| 12 | + let mut mult = vec![0; output_size]; |
| 13 | + for (i, c1) in num1.chars().rev().enumerate() { |
| 14 | + for (j, c2) in num2.chars().rev().enumerate() { |
| 15 | + let mul = c1.to_digit(10).unwrap() * c2.to_digit(10).unwrap(); |
| 16 | + // It could be a two-digit number here. |
| 17 | + mult[i + j + 1] += (mult[i + j] + mul) / 10; |
| 18 | + // Handling rounding. Here's a single digit. |
| 19 | + mult[i + j] = (mult[i + j] + mul) % 10; |
| 20 | + } |
| 21 | + } |
| 22 | + if mult[output_size - 1] == 0 { |
| 23 | + mult.pop(); |
| 24 | + } |
| 25 | + mult.iter().rev().map(|&n| n.to_string()).collect() |
| 26 | +} |
| 27 | + |
| 28 | +pub fn is_valid_nonnegative(num: &str) -> bool { |
| 29 | + num.chars().all(char::is_numeric) && !num.is_empty() && (!num.starts_with('0') || num == "0") |
| 30 | +} |
| 31 | + |
| 32 | +#[cfg(test)] |
| 33 | +mod tests { |
| 34 | + use super::*; |
| 35 | + macro_rules! test_multiply { |
| 36 | + ($($name:ident: $inputs:expr,)*) => { |
| 37 | + $( |
| 38 | + #[test] |
| 39 | + fn $name() { |
| 40 | + let (s, t, expected) = $inputs; |
| 41 | + assert_eq!(multiply(s, t), expected); |
| 42 | + assert_eq!(multiply(t, s), expected); |
| 43 | + } |
| 44 | + )* |
| 45 | + } |
| 46 | + } |
| 47 | + |
| 48 | + test_multiply! { |
| 49 | + multiply0: ("2", "3", "6"), |
| 50 | + multiply1: ("123", "456", "56088"), |
| 51 | + multiply_zero: ("0", "222", "0"), |
| 52 | + other_1: ("99", "99", "9801"), |
| 53 | + other_2: ("999", "99", "98901"), |
| 54 | + other_3: ("9999", "99", "989901"), |
| 55 | + other_4: ("192939", "9499596", "1832842552644"), |
| 56 | + } |
| 57 | + |
| 58 | + macro_rules! test_multiply_with_wrong_input { |
| 59 | + ($($name:ident: $inputs:expr,)*) => { |
| 60 | + $( |
| 61 | + #[test] |
| 62 | + #[should_panic] |
| 63 | + fn $name() { |
| 64 | + let (s, t) = $inputs; |
| 65 | + multiply(s, t); |
| 66 | + } |
| 67 | + )* |
| 68 | + } |
| 69 | + } |
| 70 | + test_multiply_with_wrong_input! { |
| 71 | + empty_input: ("", "121"), |
| 72 | + leading_zero: ("01", "3"), |
| 73 | + wrong_characters: ("2", "12d4"), |
| 74 | + wrong_input_and_zero_1: ("0", "x"), |
| 75 | + wrong_input_and_zero_2: ("y", "0"), |
| 76 | + } |
| 77 | +} |
0 commit comments