diff options
| author | Andrew Guschin <guschin.drew@gmail.com> | 2022-09-26 03:50:55 +0400 |
|---|---|---|
| committer | Andrew Guschin <guschin.drew@gmail.com> | 2022-09-26 03:50:55 +0400 |
| commit | 62f1fb7b8c748a8d57ef073980911cb7a0252b68 (patch) | |
| tree | a16bc8b53973b83b8f82d85295617bde0fb93848 | |
| parent | 4a8088e904fe46d842d37d75bacb3ed6092b6e12 (diff) | |
Рефакторинг приложения
| -rw-r--r-- | src/lab1.rs | 134 | ||||
| -rw-r--r-- | src/lab3.rs | 119 | ||||
| -rw-r--r-- | src/lab_trait.rs | 6 | ||||
| -rw-r--r-- | src/main.rs | 209 |
4 files changed, 273 insertions, 195 deletions
diff --git a/src/lab1.rs b/src/lab1.rs new file mode 100644 index 0000000..b442199 --- /dev/null +++ b/src/lab1.rs @@ -0,0 +1,134 @@ +use crate::lab_trait::Lab; +use eframe::egui; + +pub struct Window { + order: u32, + element: u32, + element_check: Option<bool>, + primitive_roots: Vec<u32>, + state: State, +} + +impl Window { + fn clear_state(&mut self) { + self.element_check = None; + self.state = State::Idle; + } +} + +impl Default for Window { + fn default() -> Self { + Self { + order: 29, + element: 2, + element_check: None, + primitive_roots: Vec::new(), + state: State::Idle, + } + } +} + +impl Lab for Window { + fn get_name(&self) -> &str { "Задача №1" } + + fn update(&mut self, ui: &mut egui::Ui) { + ui.horizontal(|ui| { + ui.label("Порядок поля: "); + if ui + .add(egui::DragValue::new(&mut self.order).clamp_range(2..=u32::MAX)) + .changed() + { + self.clear_state(); + } + }); + ui.horizontal(|ui| { + ui.label("Проверяемый элемент: "); + if ui + .add(egui::DragValue::new(&mut self.element).clamp_range(1..=self.order - 1)) + .changed() + { + self.clear_state(); + } + }); + + if ui.button("Проверить элемент").clicked() { + let min = min_order(self.element, self.order); + self.element_check = Some(min == self.order - 1); + } + match self.element_check { + Some(true) => { + ui.label("Элемент является порождающим элементом"); + } + Some(false) => { + ui.label("Элемент не является порождающим элементом"); + } + None => {} + } + + if ui.button("Рассчитать порождающие элементы").clicked() { + self.primitive_roots.clear(); + self.state = if is_prime(self.order) { + State::Running(1) + } else { + State::Error + } + } + match self.state { + State::Running(current) => { + ui.label("Вычисление..."); + let min = min_order(current, self.order); + if min == self.order - 1 { + self.primitive_roots.push(current); + } + self.state = if current == self.order - 1 { + State::Done + } else { + State::Running(current + 1) + } + } + State::Done => { + ui.label(format!( + "Порождающие элементы поля F_{}: {:?}", + self.order, self.primitive_roots + )); + } + State::Idle => {} + State::Error => { + ui.label("Можно указать только простое число!"); + } + } + } +} + +enum State { + Idle, + Running(u32), + Done, + Error, +} + +fn min_order(x: u32, order: u32) -> u32 { + let mut min = 0; + let mut pow = x; + for power in 1..order { + if pow == 1 { + min = power; + break; + } + pow = (pow * x) % order; + } + return min; +} + +fn is_prime(x: u32) -> bool { + if x <= 1 { + return false; + } + for i in 2..x / 2 + 1 { + if x % i == 0 { + return false; + } + } + return true; +} + diff --git a/src/lab3.rs b/src/lab3.rs new file mode 100644 index 0000000..b4adbf3 --- /dev/null +++ b/src/lab3.rs @@ -0,0 +1,119 @@ +use crate::lab_trait::Lab; +use eframe::egui; +use rug::{Complete, Integer}; + +enum State { + Clean, + Done +} + +pub struct Window { + str_num: String, + factors: Vec<Integer>, + state: State, +} + +impl Default for Window { + fn default() -> Self { + Self { + str_num: String::from("21894583143407671"), + factors: Vec::new(), + state: State::Clean, + } + } +} + +impl Lab for Window { + fn get_name(&self) -> &str { "Задача №3" } + + fn update(&mut self, ui: &mut egui::Ui) { + ui.horizontal(|ui| { + ui.label("Число: "); + let field = ui.add(egui::TextEdit::singleline(&mut self.str_num)); + if field.changed() { + self.state = State::Clean; + self.factors.clear(); + } + }); + if ui.button("Разложить на множители").clicked() { + let number = Integer::parse(&self.str_num).unwrap().complete(); + self.factors.append(&mut factorize(&number)); + self.state = State::Done; + } + if let State::Done = self.state { + if self.factors.len() == 1 { + ui.label(format!("Число является простым")); + } + else { + ui.label(format!("Множители: {:?}", self.factors)); + } + } + } +} + +fn factorize(n: &Integer) -> Vec<Integer> { + let mut factors = Vec::new(); + let mut front = vec![n.clone()]; + + while !front.is_empty() { + let num = front.pop().unwrap(); + match lehman(&num) { + Some(factor) => { + let other = num.div_exact_ref(&factor).complete(); + front.push(factor); + front.push(other); + }, + None => factors.push(num) + }; + } + + return factors; +} + +fn lehman(n: &Integer) -> Option<Integer> { + let one = &Integer::from(1u32); + let mut a = Integer::from(2u32); + let root3 = n.root_ref(3).complete(); + + while a <= root3 { + let (_, r) = n.div_rem_ref(&a).complete(); + if r == 0 { + return Some(a); + } + a += one; + } + + let root6 = n.root_ref(6).complete(); + let mut k = Integer::from(1u32); + while k <= root3 { + let mut d = Integer::ZERO; + let sqrtk4 = k.sqrt_ref().complete() * 4; + let (r6sk4, _) = root6.div_rem_ref(&sqrtk4).complete(); + while d <= (&r6sk4 + one).complete() { + let kn4: Integer = k.clone() * n.clone() * 4; + let sqrt_kn4 = kn4.sqrt_ref().complete(); + + let number = (sqrt_kn4.clone() + d.clone()).square() - kn4.clone(); + if number.is_perfect_square() { + let big_a = sqrt_kn4 + d.clone(); + let big_b = (big_a.square_ref() - kn4).sqrt(); + + let gcd1 = (big_a.clone() + big_b.clone()).gcd_ref(n).complete(); + let gcd2 = (big_a.clone() - big_b.clone()).gcd_ref(n).complete(); + + if &gcd1 > one && &gcd1 < n { + return Some(gcd1); + } + else if &gcd2 > one && &gcd2 < n { + return Some(gcd2); + } + } + + d += one; + } + k += one; + } + + return None; +} + diff --git a/src/lab_trait.rs b/src/lab_trait.rs new file mode 100644 index 0000000..23f110b --- /dev/null +++ b/src/lab_trait.rs @@ -0,0 +1,6 @@ +use eframe::egui; + +pub trait Lab { + fn get_name(&self) -> &str; + fn update(&mut self, ui: &mut egui::Ui); +} diff --git a/src/main.rs b/src/main.rs index b8e6eb2..832805f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ -use rug::{Complete, Integer}; +mod lab_trait; +mod lab1; +mod lab3; + +use lab_trait::Lab; use eframe::egui; -// use std::time::Instant; fn main() { let options = eframe::NativeOptions::default(); @@ -11,211 +14,27 @@ fn main() { ); } -enum State { - Idle, - Running(u32), - Done, - Error, -} - struct Application { - order: u32, - element: u32, - element_check: Option<bool>, - primitive_roots: Vec<u32>, - state: State, - - str_num: String, + labs: Vec<Box<dyn Lab>>, } impl Default for Application { fn default() -> Self { Self { - order: 29, - element: 2, - element_check: None, - primitive_roots: Vec::new(), - state: State::Idle, - - str_num: String::from("20"), - } - } -} - -fn min_order(x: u32, order: u32) -> u32 { - let mut min = 0; - let mut pow = x; - for power in 1..order { - if pow == 1 { - min = power; - break; + labs: vec![ + Box::new(lab1::Window::default()), + Box::new(lab3::Window::default()), + ], } - pow = (pow * x) % order; } - return min; -} - -fn is_prime(x: u32) -> bool { - if x <= 1 { - return false; - } - for i in 2..x / 2 + 1 { - if x % i == 0 { - return false; - } - } - return true; } impl eframe::App for Application { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - let clear_state = |app: &mut Application| { - app.element_check = None; - app.state = State::Idle; - }; - egui::Window::new("Задача №1").show(ctx, |ui| { - ui.horizontal(|ui| { - ui.label("Порядок поля: "); - if ui - .add(egui::DragValue::new(&mut self.order).clamp_range(2..=u32::MAX)) - .changed() - { - clear_state(self); - } - }); - ui.horizontal(|ui| { - ui.label("Проверяемый элемент: "); - if ui - .add(egui::DragValue::new(&mut self.element).clamp_range(1..=self.order - 1)) - .changed() - { - clear_state(self); - } - }); - - if ui.button("Проверить элемент").clicked() { - let min = min_order(self.element, self.order); - self.element_check = Some(min == self.order - 1); - } - match self.element_check { - Some(true) => { - ui.label("Элемент является порождающим элементом"); - } - Some(false) => { - ui.label("Элемент не является порождающим элементом"); - } - None => {} - } - - if ui.button("Рассчитать порождающие элементы").clicked() { - self.primitive_roots.clear(); - self.state = if is_prime(self.order) { - State::Running(1) - } else { - State::Error - } - } - match self.state { - State::Running(current) => { - ui.label("Вычисление..."); - let min = min_order(current, self.order); - if min == self.order - 1 { - self.primitive_roots.push(current); - } - self.state = if current == self.order - 1 { - State::Done - } else { - State::Running(current + 1) - } - } - State::Done => { - ui.label(format!( - "Порождающие элементы поля F_{}: {:?}", - self.order, self.primitive_roots - )); - } - State::Idle => {} - State::Error => { - ui.label("Можно указать только простое число!"); - } - } - }); - egui::Window::new("Задача №2").show(ctx, |ui| { - ui.horizontal(|ui| { - ui.label("Число: "); - ui.add(egui::TextEdit::singleline(&mut self.str_num)); - }); - if ui.button("Разложить на множители").clicked() { - let number = Integer::parse(&self.str_num).unwrap().complete(); - let factors = factorize(&number); - println!("Множители: {:?}", factors); - } - }); - } -} - -fn factorize(n: &Integer) -> Vec<Integer> { - let mut factors = Vec::new(); - let mut front = vec![n.clone()]; - - while !front.is_empty() { - let num = front.pop().unwrap(); - match lehman(&num) { - Some(factor) => { - let other = num.div_exact_ref(&factor).complete(); - front.push(factor); - front.push(other); - }, - None => factors.push(num) - }; - } - - return factors; -} - -fn lehman(n: &Integer) -> Option<Integer> { - let one = &Integer::from(1u32); - let mut a = Integer::from(2u32); - let root3 = n.root_ref(3).complete(); - - while a <= root3 { - let (_, r) = n.div_rem_ref(&a).complete(); - if r == 0 { - return Some(a); + for window in &mut self.labs { + egui::Window::new(window.get_name()) + .show(ctx, |ui| window.update(ui)); } - a += one; } - - let root6 = n.root_ref(6).complete(); - let mut k = Integer::from(1u32); - while k <= root3 { - let mut d = Integer::ZERO; - let sqrtk4 = k.sqrt_ref().complete() * 4; - let (r6sk4, _) = root6.div_rem_ref(&sqrtk4).complete(); - while d <= (&r6sk4 + one).complete() { - let kn4: Integer = k.clone() * n.clone() * 4; - let sqrt_kn4 = kn4.sqrt_ref().complete(); - - let number = (sqrt_kn4.clone() + d.clone()).square() - kn4.clone(); - if number.is_perfect_square() { - let big_a = sqrt_kn4 + d.clone(); - let big_b = (big_a.square_ref() - kn4).sqrt(); - - let gcd1 = (big_a.clone() + big_b.clone()).gcd_ref(n).complete(); - let gcd2 = (big_a.clone() - big_b.clone()).gcd_ref(n).complete(); - - if &gcd1 > one && &gcd1 < n { - return Some(gcd1); - } - else if &gcd2 > one && &gcd2 < n { - return Some(gcd2); - } - } - - d += one; - } - k += one; - } - - return None; } + |