Skip to content

Instantly share code, notes, and snippets.

@AnthonyMikh
Last active March 26, 2018 19:01
Show Gist options
  • Save AnthonyMikh/b8ec7cb67ab9725c50c17d08a72be107 to your computer and use it in GitHub Desktop.
Save AnthonyMikh/b8ec7cb67ab9725c50c17d08a72be107 to your computer and use it in GitHub Desktop.
Решение задачи №81 от UniLecs
#![deny(overflowing_literals)]
#[macro_use]
//Библиотека для ленивой инициализации. Позволяет удостовериться,
//что IS_PRIME инициализируется только один раз
extern crate lazy_static;
//Верхняя граница на входные данные
const BOUND: usize = 1_000;
const IS_PRIME_SIZE: usize = BOUND - 2 + 1;
//Элемент IS_PRIME с индексом i содержит ответ на вопрос
//"является ли i+2 простым". Память под числа 0 и 1 не выделяется.
//Массив PRIMES содержит простые числа.
lazy_static! {
static ref IS_PRIME: [bool; IS_PRIME_SIZE] = make_is_prime();
static ref PRIMES: Box<[usize]> = make_primes();
}
//Инициализация массива для теста на простоту
fn make_is_prime() -> [bool; IS_PRIME_SIZE] {
let mut is_prime = [false; IS_PRIME_SIZE];
is_prime[0] = true; //2 -- простое число
//Для всех нечётных чисел от 3 до IS_PRIME_SIZE
for num in (3..IS_PRIME_SIZE).filter(|&x| x % 2 != 0) {
is_prime[num-2] = is_prime[0..num-2]
.iter()
.zip(2..)
.filter(|&(&x, _)| x) //отбираем все простые до num
.all(|(_, i)| num % i != 0) //и проверяем, являются ли они делителями
}
is_prime
}
//Инициализация массива простых чисел
fn make_primes() -> Box<[usize]> {
IS_PRIME.iter()
.zip(2..)
.filter(|&(&elem, _)| elem)
.map(|(_, i)| i)
.collect::<Vec<_>>()
.into_boxed_slice()
}
//Проверяет, является ли число простым, используя IS_PRIME
fn is_prime(x: usize) -> bool {
match x {
0 | 1 => false,
_other => IS_PRIME[x-2],
}
}
#[derive(PartialEq, Debug)]
//Тип возможной ошибки при факторизации
enum FactorizeErr {
Zero, //Передан ноль
One, //Передана единица
OutOfBound, //Передано число больше BOUND
}
//Разложение -- это вектор пар: первое число -- простой
//множитель, второе -- степень
type Decomposition = Vec<(usize, usize)>;
//Раскладывает число на простые множители
fn prime_factorize(x: usize) -> Result<Decomposition, FactorizeErr> {
use FactorizeErr::*;
if x == 0 { return Err(Zero) }
if x == 1 { return Err(One) }
if x > BOUND { return Err(OutOfBound) }
//Если число простое, то разложение тривиально -- само число
//в первой степени
if is_prime(x) { return Ok(vec![(x, 1)]) }
let mut x = x;
let mut decompose = Vec::new();
//Отбираем простые числа
let mut primes = (2..).filter(|&i| is_prime(i));
while x != 1 {
//Получаем очередное простое число
let prime = primes.next().unwrap();
let mut power = 0;
while x % prime == 0 { //Пока x делится на простое --
x /= prime; //делим
power += 1; //и подсчитываем число делений
}
if power != 0 { //Если prime входит в разложение --
decompose.push((prime, power)); //добавляем
}
}
Ok(decompose)
}
#[test]
//Проверяем, что для всех подсчитанных простых чисел
//разложение тривиально
fn check_primes() {
for i in 2..BOUND+1 {
if is_prime(i) {
assert_eq!(prime_factorize(i), Ok(vec![(i, 1)]));
}
}
}
#[test]
fn some_variants() {
assert_eq!(prime_factorize(525), Ok(vec![(3, 1), (5, 2), (7, 1)]));
assert_eq!(prime_factorize(366), Ok(vec![(2, 1), (3, 1), (61, 1)]));
assert_eq!(prime_factorize(199), Ok(vec![(199, 1)]));
}
#[test]
//Проверяем, что ошибки корректно обрабатываются
fn check_errors() {
use FactorizeErr::*;
assert_eq!(prime_factorize(0), Err(Zero));
assert_eq!(prime_factorize(1), Err(One));
assert_eq!(prime_factorize(BOUND + 1), Err(OutOfBound));
}
@AnthonyMikh
Copy link
Author

AnthonyMikh commented Mar 25, 2018

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