Решение на Bigint от Петър Милев

Обратно към всички решения

Към профила на Петър Милев

Резултати

  • 14 точки от тестове
  • 0 бонус точки
  • 14 точки общо
  • 14 успешни тест(а)
  • 1 неуспешни тест(а)

Код

use std::str::FromStr;
use std::cmp::Ordering;
use std::ops::{Add, Sub, Neg};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Bigint {
sign: i8,
digits: Vec<u8>,
}
impl Bigint {
/// Конструира нов Bigint със стойност "0" и положителен знак.
/// Това може да означава празен вектор с цифри или масив с една цифра `0` -- ваш избор.
///
pub fn new() -> Self {
Bigint { sign: 1, digits: vec![0] }
}
fn from_components(mut digits: Vec<u8>, sign: i8) -> Self {
while digits.len() != 0 && digits[0] == 0 {
digits.iter()
.position(|&e| e == 0)
.map(|p| digits.remove(p));
}
if digits.len() == 0 {
return Self::new();
}
Bigint { sign: sign, digits: digits.to_vec() }
}
/// Връща `true` ако числото е положително. Нулата не е положителна.
pub fn is_positive(&self) -> bool {
self.sign > 0
}
/// Връща `true` ако числото е отрицателно. Нулата не е отрицателна.
pub fn is_negative(&self) -> bool {
self.sign < 0
}
fn cmp_abs(&self, other: &Bigint) -> Ordering {
if self.digits.len() > other.digits.len() {
return Ordering::Greater;
} else if self.digits.len() < other.digits.len() {
return Ordering::Less;
}
for i in 0..self.digits.len() {
match self.digits[i].cmp(&other.digits[i]) {
Ordering::Greater => return Ordering::Greater,
Ordering::Less => return Ordering::Less,
_ => ()
}
}
Ordering::Equal
}
}
#[derive(Debug)]
pub struct ParseError;
impl FromStr for Bigint {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut sign: i8 = 1;
let mut digits = vec![];
for (i, c) in s.chars().enumerate() {
if i == 0 {
match c {
'-' => {
sign = -1;
continue;
},
'+' => continue,
_ => ()
}
}
match c.to_digit(10) {
Some(d) => digits.push(d as u8),
None => return Err(Self::Err{})
}
}
Ok(Self::from_components(digits, sign))
}
}
impl PartialOrd for Bigint {
/// Две цели числа винаги могат да се сравнят, така че "частичното" равенство е същото като
/// пълното.
///
fn partial_cmp(&self, other: &Bigint) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Bigint {
fn cmp(&self, other: &Bigint) -> Ordering {
if self.is_positive() != other.is_positive() {
if self.is_positive() {
return Ordering::Greater;
} else {
return Ordering::Less;
}
}
let res = self.cmp_abs(other);
if self.is_negative() {
return res.reverse();
}
res
}
}
impl Neg for Bigint {
type Output = Bigint;
fn neg(self) -> Self::Output {
Self::from_components(self.digits, -self.sign)
}
}
impl Add for Bigint {
type Output = Bigint;
fn add(self, other: Self) -> Self {
let mut res: Vec<u8> = vec![];
let (greater, less) = match self.cmp_abs(&other) {
Ordering::Greater => (&self, &other),
_ => (&other, &self)
};
let g_iter = greater.digits.iter().rev();
let mut l_iter = less.digits.iter().rev();
let sign: i8 = greater.sign * less.sign;
let mut one_in_mind: i8 = 0;
for i in g_iter {
let g_digit = *i as i8;
let l_digit = match l_iter.next() {
Some(d) => *d as i8,
None => 0
};
let new_digit = g_digit + sign * l_digit + one_in_mind;
// println!("1: {} {} = {} | {}", g_digit, l_digit, new_digit, one_in_mind);
res.push(((new_digit + 10) % 10) as u8);
one_in_mind = if (0..10).contains(&new_digit) { 0 } else { sign }; // sign can be new_digit.signum()
}
res.push(one_in_mind as u8);
res.reverse();
Bigint::from_components(res, greater.sign)
}
}
impl Sub for Bigint {
type Output = Bigint;
fn sub(self, other: Self) -> Self {
self + (-other)
}
}
// for printing Bigint
impl std::fmt::Display for Bigint {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}{}", if self.sign == -1 { "-" } else { "" }, self.digits.iter().map(|el| el.to_string()).collect::<String>())
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20201127-2274206-1o7jwza/solution)
    Finished test [unoptimized + debuginfo] target(s) in 1.77s
     Running target/debug/deps/solution_test-589a43f0f4b10ca3

running 15 tests
test solution_test::test_bigint_construction ... ok
test solution_test::test_bigint_nonzero_sign ... ok
test solution_test::test_bigint_zero_sign ... FAILED
test solution_test::test_comparison ... ok
test solution_test::test_invalid_string ... ok
test solution_test::test_neutralization ... ok
test solution_test::test_parsing_with_and_without_sign ... ok
test solution_test::test_parsing_with_leading_zeroes ... ok
test solution_test::test_sub_1_basic ... ok
test solution_test::test_sub_2_diferent_lengths ... ok
test solution_test::test_sub_3_carry ... ok
test solution_test::test_sum_1_basic ... ok
test solution_test::test_sum_2_different_lengths ... ok
test solution_test::test_sum_3_overflow ... ok
test solution_test::test_sum_4_negative ... ok

failures:

---- solution_test::test_bigint_zero_sign stdout ----
thread 'main' panicked at 'assertion failed: !zero.is_positive()', tests/solution_test.rs:21:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    solution_test::test_bigint_zero_sign

test result: FAILED. 14 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--test solution_test'

История (1 версия и 0 коментара)

Петър качи първо решение на 26.11.2020 05:49 (преди 8 месеца)