Решение на Bigint от Васил Папукчиев

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

Към профила на Васил Папукчиев

Резултати

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

Код

#[derive(Debug, PartialEq, Eq)]
pub struct Bigint {
sign: i8,
digits: Vec<u8>,
}
impl Bigint {
pub fn new() -> Self {
Bigint { sign: 1, digits: vec![0] }
}
fn from_components(digits: Vec<u8>, sign: i8) -> Self {
if sign != 1 && sign != -1 {
panic!();
}
if digits.len() == 1 && digits[0] == 0 {
return Bigint::new();
}
let mut trimed_digits: Vec<u8> = Vec::new();
let mut should_add = false;
for digit in digits {
if digit == 0 {
if should_add {
trimed_digits.push(digit);
}
}
else {
should_add = true;
trimed_digits.push(digit);
}
}
Bigint { sign, digits: trimed_digits }
}
pub fn is_positive(&self) -> bool {
match self.sign {
1 => true,
-1 => false,
_ => panic!(),
}
}
pub fn is_negative(&self) -> bool {
match self.sign {
1 => false,
-1 => true,
_ => panic!(),
}
}
}
use std::str::FromStr;
#[derive(Debug)]
pub struct ParseError;
impl FromStr for Bigint {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Ok(Bigint::new());
}
let first_char = s.chars().next().unwrap();
let sign: i8;
let mut first_trimed_s = s;
match first_char {
'-' => { sign = -1; first_trimed_s = &s[1..] },
'+' => { sign = 1; first_trimed_s = &s[1..] },
_ => sign = 1
}
let trimed_s = first_trimed_s.trim_start_matches('0');
if trimed_s.is_empty() {
Ok(Bigint::new())
}
else {
let mut digits: Vec<u8> = Vec::new();
for single_char in trimed_s.chars() {
if single_char.is_digit(10) {
digits.push(single_char.to_digit(10).unwrap() as u8);
}
else {
return Err(ParseError {});
}
}
Ok(Bigint::from_components(digits, sign))
}
}
}
use std::cmp::Ordering;
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 {
let mut ordering = Ordering::Equal;
if self.sign != other.sign {
ordering = self.sign.cmp(&other.sign);
}
else {
let first_length = self.digits.len();
let second_length = other.digits.len();
if first_length != second_length {
ordering = first_length.cmp(&second_length);
}
else {
for i in 0..first_length {
if self.digits[i] != other.digits[i] {
ordering = self.digits[i].cmp(&other.digits[i]);
break;
}
}
}
}
if self.sign == -1 && other.sign == -1 {
match ordering {
Ordering::Less => return Ordering::Greater,
Ordering::Greater => return Ordering::Less,
_ => return Ordering::Equal,
}
}
ordering
}
}
use std::ops::{Add, Sub};
impl Add for Bigint {
type Output = Bigint;
fn add(self, other: Self) -> Self {
if self.sign == other.sign {
let mut digits: Vec<u8> = Vec::new();
let mut bigger_number: Vec<u8>;
let mut smaller_number: Vec<u8>;
if self > other {
bigger_number = self.digits.clone();
bigger_number.reverse();
smaller_number = other.digits.clone();
smaller_number.reverse();
}
else {
bigger_number = other.digits.clone();
bigger_number.reverse();
smaller_number = self.digits.clone();
smaller_number.reverse();
}
let mut should_add_one = false;
for i in 0..bigger_number.len() {
let first_number = bigger_number[i];
let second_number: u8;
if i < smaller_number.len() {
second_number = smaller_number[i];
}
else {
second_number = 0;
}
let number: u8;
let add_number = should_add_one as u8;
if first_number + add_number + second_number > 9 {
number = first_number + add_number + second_number - 10;
should_add_one = true;
}
else {
number = first_number + add_number + second_number;
should_add_one = false;
}
digits.push(number);
}
if should_add_one {
digits.push(1);
}
digits.reverse();
Bigint::from_components(digits, self.sign)
}
else {
let mut digits: Vec<u8> = Vec::new();
let sign: i8;
let mut bigger_number: Vec<u8>;
let mut smaller_number: Vec<u8>;
if Bigint::from_components(self.digits.clone(), 1) > Bigint::from_components(other.digits.clone(), 1) {
bigger_number = self.digits.clone();
bigger_number.reverse();
smaller_number = other.digits.clone();
smaller_number.reverse();
sign = self.sign;
}
else if Bigint::from_components(self.digits.clone(), 1) < Bigint::from_components(other.digits.clone(), 1) {
bigger_number = other.digits.clone();
bigger_number.reverse();
smaller_number = self.digits.clone();
smaller_number.reverse();
sign = other.sign;
}
else {
return Bigint::new();
}
let mut should_sub_one = false;
for i in 0..bigger_number.len() {
let first_number = bigger_number[i];
let second_number: u8;
if i < smaller_number.len() {
second_number = smaller_number[i];
}
else {
second_number = 0;
}
let number: u8;
let sub_number: u8 = should_sub_one as u8;
if first_number - sub_number < second_number {
number = 10 + first_number - sub_number - second_number;
should_sub_one = true;
}
else {
number = first_number - sub_number - second_number;
should_sub_one = false;
}
digits.push(number);
}
digits.reverse();
Bigint::from_components(digits, sign)
}
}
}
impl Sub for Bigint {
type Output = Bigint;
fn sub(self, other: Self) -> Self {
self + Bigint::from_components(other.digits, other.sign * -1)
}
}

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

Compiling solution v0.1.0 (/tmp/d20201127-2274206-1tu2mm5/solution)
    Finished test [unoptimized + debuginfo] target(s) in 1.63s
     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 ... FAILED
test solution_test::test_sum_1_basic ... ok
test solution_test::test_sum_2_different_lengths ... ok
test solution_test::test_sum_3_overflow ... FAILED
test solution_test::test_sum_4_negative ... FAILED

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

---- solution_test::test_sub_3_carry stdout ----
thread 'main' panicked at 'attempt to subtract with overflow', src/lib.rs:250:20

---- solution_test::test_sum_3_overflow stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `Bigint { sign: -1, digits: [1, 0] }`,
 right: `Bigint { sign: -1, digits: [1, 0, 0, 0] }`', tests/solution_test.rs:100:5

---- solution_test::test_sum_4_negative stdout ----
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `Bigint { sign: -1, digits: [1, 2] }`,
 right: `Bigint { sign: -1, digits: [1, 2, 0, 1, 2] }`', tests/solution_test.rs:113:5


failures:
    solution_test::test_bigint_zero_sign
    solution_test::test_sub_3_carry
    solution_test::test_sum_3_overflow
    solution_test::test_sum_4_negative

test result: FAILED. 11 passed; 4 failed; 0 ignored; 0 measured; 0 filtered out

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

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

Васил качи първо решение на 27.11.2020 00:01 (преди 8 месеца)