Skip to content

Instantly share code, notes, and snippets.

@AnthonyMikh
Last active February 9, 2018 10:40
Show Gist options
  • Save AnthonyMikh/4cd92ccd70e4ae7d67e48784f7036e51 to your computer and use it in GitHub Desktop.
Save AnthonyMikh/4cd92ccd70e4ae7d67e48784f7036e51 to your computer and use it in GitHub Desktop.
Решение задачи №68 от UniLecs на Rust
//Постоянный пересчёт чисел Фибоначчи слишком неэффективен,
//поэтому заведём отдельный буфер для хранения уже вычисленных
//чисел, а чтобы не испортить случайно значения, заведём для
//буфера отдельный модуль
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));
}
@AnthonyMikh
Copy link
Author

AnthonyMikh commented Feb 7, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment