summaryrefslogtreecommitdiff
path: root/labs/src/lab3.rs
blob: 7fda28e63a9c22d40b89c727981823c7cf40d0a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::lab_trait::Lab;
use eframe::egui;
use rug::{Complete, Integer};

enum State {
    Clean,
    Done,
    Error,
}

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() {
            self.factors.clear();
            match Integer::parse(&self.str_num) {
                Ok(number) => {
                    self.factors.append(&mut factorize(&number.complete()));
                    self.state = State::Done;
                }
                Err(_) => self.state = State::Error,
            };
        }
        if let State::Done = self.state {
            if self.factors.len() == 1 {
                ui.label(format!("Число является простым"));
            } else {
                ui.label(format!("Множители: {:?}", self.factors));
            }
        }
        if let State::Error = self.state {
            ui.label("В числе имеются недопустимые символы");
        }
    }
}

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;
}