Last active
February 9, 2018 10:40
-
-
Save AnthonyMikh/4cd92ccd70e4ae7d67e48784f7036e51 to your computer and use it in GitHub Desktop.
Решение задачи №68 от UniLecs на Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Постоянный пересчёт чисел Фибоначчи слишком неэффективен, | |
//поэтому заведём отдельный буфер для хранения уже вычисленных | |
//чисел, а чтобы не испортить случайно значения, заведём для | |
//буфера отдельный модуль | |
mod fib { | |
//Тип числа, в котором хранятся вычисленные значения. | |
//Выбирается исходя из критерия F(INDEX_BOUND+1) <= Base::max_value(), | |
//где F(n) - n-ое число Фибоначчи | |
pub type Base = u32; | |
pub struct FibAccum { //Буфер вычисленных значений. | |
inner: Vec<Base>, //Обратите внимание, поле не публично, поэтому | |
//его можно поменять только через функции | |
} | |
impl FibAccum { | |
pub fn new() -> Self { //Создаёт буфер и заполняет начальными | |
let mut seed = Vec::new(); //значениями | |
seed.push(0); // == F(0) | |
seed.push(1); // == F(1) | |
FibAccum { inner: seed } | |
} | |
pub fn nth(&mut self, i: usize) -> Base { | |
if i >= self.inner.len() { //Если данное значение ещё не вычисленно, | |
self.inner.reserve(i); //то резервируем место в памяти под | |
//элементы с 0-го по i-ый, | |
let a = self.nth(i-2); //считаем два предыдущих значения и | |
let b = self.nth(i-1); //записываем их сумму. | |
self.inner.push(a + b); | |
} //К этому моменту i-ое значение есть в буфере. | |
self.inner[i] //Возвращаем i-ое значение | |
} | |
} | |
} | |
//Верхняя граница возможных значений индексов | |
const INDEX_BOUND: usize = 30; | |
//Возможные ошибки при вычислении решения. | |
//Аннотация #[derive(Debug, PartialEq)] предписывает | |
//сгенерировать код для сравнения и отладочного | |
//вывода на печать | |
#[derive(Debug, PartialEq)] | |
enum TwoDigitsError { | |
IndexIsTooLarge, | |
} | |
impl fib::FibAccum { | |
//Возвращает число последовательностей, заданных условием задачи, | |
//для данной длины или ошибку, если длина больше ограничения | |
fn two_digits(&mut self, n: usize) -> Result<fib::Base, TwoDigitsError> { | |
if n > INDEX_BOUND { | |
return Err(TwoDigitsError::IndexIsTooLarge) | |
} | |
Ok(2*self.nth(n+1)) | |
} | |
} | |
//Функции, помеченные аннотацией #[test], предназначены для, как ни странно, тестирования. | |
//Их можно запустить командой cargo test. | |
//Именно эта команда запускается на play.rust-lang.org, если функция main не найдена. | |
//В реальном проекте эти функции были бы вынесены в отдельный модуль | |
#[test] | |
fn do_tests() { | |
use fib::*; | |
use TwoDigitsError::*; | |
let mut acc = FibAccum::new(); | |
//Макрос assert_eq! разворачивается в код, который сравнивает значения аргументов | |
//и паникует, если они не равны. | |
assert_eq!(acc.two_digits(1), Ok(2)); | |
assert_eq!(acc.two_digits(2), Ok(4)); | |
assert_eq!(acc.two_digits(3), Ok(6)); | |
assert_eq!(acc.two_digits(4), Ok(10)); | |
assert_eq!(acc.two_digits(INDEX_BOUND+1), Err(IndexIsTooLarge)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Playground: https://play.rust-lang.org/?gist=d02dde35e986d4812290ae5281fea4ed&version=stable