number_based/
utils.rs

1use crate::graphemes::grapheme_creation::GRAPHEMES;
2
3pub fn vec_to_arr<T, const N: usize>(v: Vec<T>) -> [T; N] {
4    v.try_into()
5        .unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
6}
7
8pub fn from_string(base: u16, number: &str) -> Vec<u16> {
9    if base > GRAPHEMES.len() as u16 {
10        panic!("There are not enough graphemes create number. Use a lower base");
11    }
12    // digits is the vector that will be returned in the uBase instance
13    let number = number.trim();
14    let digits: Vec<u16> = number
15        .split("")
16        .filter(|s| s != &"")
17        .map(|s| {
18            let byte_arr = s.as_bytes();
19            let mut byte_vec: Vec<u8> = Vec::new();
20            // the byte array must match [u8; 4], so we fill the rest of the array with zeros
21            byte_vec.resize(4 - byte_arr.len(), 0);
22            // fill the array, ending up with a Vec<u8> of length 4
23            for byte in byte_arr {
24                byte_vec.push(*byte);
25            }
26
27            let comp_arr = &vec_to_arr(byte_vec);
28
29            // find the associated key to the grapheme provided in the string
30            if let Some(key) =
31                GRAPHEMES
32                    .iter()
33                    .find_map(|(key, val)| if val == comp_arr { Some(key) } else { None })
34            {
35                if *key > base - 1 {
36                    let error = String::from("value ")
37                        + number
38                        + "  contains graphemes greater than number base "
39                        + &base.to_string();
40                    panic!("{error}");
41                }
42                *key
43            } else {
44                let error = String::from("value ") + number + " not in valid graphemes";
45                panic!("{error}");
46            }
47        })
48        .collect();
49
50    digits
51}
52
53pub fn add(base: u16, numb1: &[u16], numb2: &[u16]) -> Vec<u16> {
54    let mut numb1 = numb1.to_owned();
55    numb1.reverse();
56    let mut numb2 = numb2.to_owned();
57    numb2.reverse();
58
59    let mut res: Vec<u16> = Vec::new();
60
61    let (greatest, smallest) = if numb1.len() > numb2.len() {
62        (&numb1, &numb2)
63    } else {
64        (&numb2, &numb1)
65    };
66
67    for i in 0..smallest.len() {
68        res.push(greatest[i] + smallest[i]);
69    }
70    for digit in greatest.iter().skip(smallest.len()) {
71        res.push(*digit);
72    }
73
74    for i in 0..res.len() {
75        if res[i] >= base {
76            // means we need to add another digit
77            if i == res.len() - 1 {
78                res.push(1);
79            } else {
80                res[i + 1] += 1;
81            }
82            res[i] -= base;
83        }
84    }
85
86    res.reverse();
87    res
88}
89
90/// sebtraction will assume that numb1 >= numb2
91pub fn subtract(base: u16, numb1: &[u16], numb2: &[u16]) -> Vec<u16> {
92    let mut numb1 = numb1.to_owned();
93    numb1.reverse();
94    let mut numb2 = numb2.to_owned();
95    numb2.reverse();
96
97    let mut res: Vec<i32> = Vec::new();
98
99    for i in 0..numb2.len() {
100        res.push(numb1[i] as i32 - numb2[i] as i32);
101    }
102    for digit in numb1.iter().skip(numb2.len()) {
103        res.push(*digit as i32);
104    }
105
106    for i in 0..res.len() {
107        if res[i] < 0 {
108            res[i + 1] -= 1;
109            res[i] += base as i32;
110        }
111    }
112
113    while res.last() == Some(&0_i32) {
114        res.pop();
115    }
116
117    res.reverse();
118
119    res.iter().map(|x| x.to_owned() as u16).collect()
120}
121
122pub fn trim_base_vec(vec: &mut Vec<u16>) -> Vec<u16> {
123    vec.reverse();
124    while vec.last() == Some(&0_u16) {
125        vec.pop();
126    }
127    vec.reverse();
128    vec.to_owned()
129}
130
131pub fn greater_than(numb1: &[u16], numb2: &[u16]) -> bool {
132    let numb1 = trim_base_vec(&mut numb1.to_owned());
133    let numb2 = trim_base_vec(&mut numb2.to_owned());
134    if numb1.len() > numb2.len() {
135        return true;
136    } else if numb1.len() == numb2.len() {
137        for i in 0..numb1.len() {
138            if numb1[i] > numb2[i] {
139                return true;
140            } else if numb2[i] > numb1[i] {
141                return false;
142            }
143        }
144        false
145    } else {
146        false
147    }
148}
149
150fn convert_base10(base: u16, numb: &[u16]) -> u128 {
151    let mut numb = numb.to_owned();
152    numb.reverse();
153    let mut res: u128 = 0;
154    for i in 0..numb.len() {
155        res += numb[i as usize] as u128 * (base as u128).pow(i as u32) as u128;
156    }
157    res
158}
159
160pub fn div(base: u16, numb1: &[u16], numb2: &[u16]) -> (Vec<u16>, Vec<u16>) {
161    let mut numb1 = numb1.to_owned();
162    let mut numb2 = numb2.to_owned();
163
164    // prepare the numbers
165    trim_base_vec(&mut numb1);
166    trim_base_vec(&mut numb2);
167
168    // if the divisor is greater than the divident, there is no reason to perform a comprehensive
169    // calculation, we can simply return 0 as the quotient and the divident as the remainder
170    if greater_than(&numb2, &numb1) {
171        return (vec![0], numb1);
172    }
173
174    let mut quo: Vec<u16> = Vec::new();
175    let mut divident: Vec<u16> = Vec::new();
176    for numb in &numb1 {
177        divident.push(*numb);
178        if greater_than(&numb2, &divident) {
179            quo.push(0);
180        } else {
181            // note that here, the numbers are of the same length
182            // convert numbers to base 10
183            let divident_base10 = convert_base10(base, &divident);
184            let divisor_base10 = convert_base10(base, &numb2);
185            let res = (divident_base10 / divisor_base10) as u16;
186            quo.push(res);
187
188            // prepare divident for next iteration
189            divident = subtract(base, &divident, &mul(base, &vec![res], &numb2));
190        }
191    }
192
193    let remainder = trim_base_vec(&mut subtract(base, &numb1, &mul(base, &quo, &numb2)));
194
195    (quo, remainder)
196}
197
198pub fn mul(base: u16, number1: &[u16], number2: &[u16]) -> Vec<u16> {
199    let numb1 = if greater_than(number1, number2) {
200        let mut numb1 = number1.to_owned();
201        numb1.reverse();
202        numb1
203    } else {
204        let mut numb2 = number2.to_owned();
205        numb2.reverse();
206        numb2
207    };
208
209    let numb2 = if !greater_than(number1, number2) {
210        let mut numb1 = number1.to_owned();
211        numb1.reverse();
212        numb1
213    } else {
214        let mut numb2 = number2.to_owned();
215        numb2.reverse();
216        numb2
217    };
218
219    let mut mul_pieces: Vec<Vec<u16>> = Vec::new();
220
221    for digit2 in numb2 {
222        let mut mul_piece: Vec<u16> = Vec::new();
223        let mut waiting_value: u16 = 0;
224        let mut placing_value: u16;
225        for digit1 in &numb1 {
226            let product = digit1 * digit2;
227            placing_value = waiting_value + (product - (product / base) * base);
228            waiting_value = product / base;
229
230            if placing_value >= base {
231                placing_value -= base;
232                waiting_value += 1;
233            }
234            mul_piece.push(placing_value);
235        }
236        if waiting_value != 0 {
237            mul_piece.push(waiting_value);
238        }
239        mul_piece.reverse();
240        mul_pieces.push(mul_piece);
241    }
242
243    for (i, piece) in mul_pieces.iter_mut().enumerate() {
244        for _ in 0..i {
245            piece.push(0);
246        }
247    }
248
249    let mut res: Vec<u16> = vec![];
250    for piece in mul_pieces {
251        res = add(base, &res, &piece);
252    }
253
254    trim_base_vec(&mut res)
255}
256
257fn as_base10(base: u16, mut numb: Vec<u16>) -> u16 {
258    let mut res: u128 = 0;
259    numb.reverse();
260
261    for (i, digit) in numb.iter().enumerate() {
262        res += *digit as u128 * (base as u128).pow(i as u32);
263    }
264
265    res as u16
266}
267
268fn from_base10(base: u16, mut numb: u16) -> Vec<u16> {
269    let mut res: Vec<u16> = Vec::new();
270    while numb > 0 {
271        res.push(numb % base);
272        numb /= base;
273    }
274
275    res.reverse();
276    res
277}
278
279pub fn convert(self_base: u16, self_digits: Vec<u16>, base: u16) -> Vec<u16> {
280    if base > GRAPHEMES.len() as u16 {
281        panic!("Cannot convert. Requested base is greater than number of graphemes.");
282    }
283    // convert input base to self.base so that we can perform division in self.base
284    let mut base_as_self = from_base10(self_base, base);
285
286    let mut res: Vec<u16> = Vec::new();
287
288    let mut numb = self_digits;
289    while greater_than(&numb, &base_as_self)
290        || trim_base_vec(&mut numb) == trim_base_vec(&mut base_as_self)
291    {
292        let (quotient, rem) = div(self_base, &numb, &base_as_self);
293        numb = quotient;
294        res.push(as_base10(self_base, rem));
295    }
296    res.push(as_base10(self_base, numb));
297
298    res.reverse();
299    res
300}