1use crate::{Base, BigNumBase, SigRange};
4
5pub trait Succ {
9 fn succ(self) -> Self;
10}
11
12pub trait Pred {
16 fn pred(self) -> Self;
17}
18
19impl<T> Succ for BigNumBase<T>
20where
21 T: Base,
22{
23 fn succ(self) -> Self {
24 let SigRange(min_sig, max_sig) = self.base.sig_range();
25
26 if self.sig == max_sig {
27 Self {
28 sig: min_sig,
29 exp: self.exp + 1,
30 base: self.base,
31 }
32 } else {
33 Self {
34 sig: self.sig + 1,
35 ..self
36 }
37 }
38 }
39}
40
41impl<T> Pred for BigNumBase<T>
42where
43 T: Base,
44{
45 fn pred(self) -> Self {
46 let SigRange(min_sig, max_sig) = self.base.sig_range();
47
48 if self.exp == 0 {
49 if self.sig == 0 {
50 panic!("Cannot get the predecessor of 0");
51 }
52
53 Self {
54 sig: self.sig - 1,
55 ..self
56 }
57 } else if self.sig == min_sig {
58 Self {
59 sig: max_sig,
60 exp: self.exp - 1,
61 base: self.base,
62 }
63 } else {
64 Self {
65 sig: self.sig - 1,
66 ..self
67 }
68 }
69 }
70}
71
72pub trait BigNumPow<T>
73where
74 T: Base,
75{
76 fn pow(self, n: i32) -> BigNumBase<T>;
77}
78
79impl<T> BigNumPow<T> for f64
80where
81 T: Base,
82{
83 fn pow(self, n: i32) -> BigNumBase<T> {
84 let mut res: BigNumBase<T> = 1u64.into();
85
86 let max_pow = f64::MAX.log(T::NUMBER as f64).floor() as i32 - 1;
87
88 if n <= max_pow {
89 res *= self.powi(n);
90 } else {
91 let mut remaining_pow = n;
92 let mut divisions = 0;
93
94 loop {
95 if remaining_pow <= max_pow {
96 res *= self.powi(remaining_pow);
98 for _ in 0..divisions {
99 res *= res;
100 }
101 break;
102 } else if remaining_pow <= max_pow * 25 {
103 remaining_pow -= max_pow;
104 res *= self.powi(max_pow);
105 } else {
106 remaining_pow /= 2;
107 divisions += 1;
108 }
109 }
110 }
111
112 res
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 use crate::{
121 create_default_base, macros::test_macros::assert_eq_bignum, BigNumBase, BigNumBin, Binary,
122 };
123
124 #[test]
126 fn test_succ() {
127 type BigNum = BigNumBase<Binary>;
128 let SigRange(min_sig, max_sig) = Binary::calculate_ranges().1;
129
130 assert_eq_bignum!(BigNum::new(0, 0).succ(), BigNum::new(1, 0));
131 assert_eq_bignum!(BigNum::new(max_sig, 0).succ(), BigNum::new(min_sig, 1));
132 assert_eq_bignum!(BigNum::new(max_sig, 1).succ(), BigNum::new(min_sig, 2));
133 }
134
135 #[test]
136 fn test_pred() {
137 type BigNum = BigNumBase<Binary>;
138 let SigRange(min_sig, max_sig) = Binary::calculate_ranges().1;
139
140 assert_eq_bignum!(BigNum::new(1, 0).pred(), BigNum::new(0, 0));
141 assert_eq_bignum!(BigNum::new(min_sig, 1).pred(), BigNum::new(max_sig, 0));
142 assert_eq_bignum!(BigNum::new(min_sig, 2).pred(), BigNum::new(max_sig, 1));
143 }
144
145 #[test]
146 fn test_bignum_pow() {
147 type BigNum = BigNumBase<Binary>;
148 create_default_base!(Base3, 3);
149 type BigNum3 = BigNumBase<Base3>;
150 create_default_base!(Base1422, 1422);
151 type BigNum1422 = BigNumBase<Base1422>;
152
153 let res: BigNum = 2.0.pow(1000);
154 let res3: BigNum3 = 3.0.pow(1000);
155 let res1422: BigNum1422 = 1422.0.pow(1000);
156
157 assert!(res.fuzzy_eq(BigNum::new(1, 1000), 1000));
158 assert!(res3.fuzzy_eq(BigNum3::new(1, 1000), 1000000));
159 assert!(
160 res1422.fuzzy_eq(BigNum1422::new(1, 1000), 1000000),
161 "{:?} {:?}",
162 res1422,
163 BigNum1422::new(1, 1000)
164 );
165 }
166
167 #[test]
168 fn test_bignum_pow2() {
169 type BigNum = BigNumBin;
170 assert_eq!(2f64.pow(10), BigNum::from(1024));
171 assert_eq!(2f64.pow(20), BigNum::from(1024 * 1024));
172
173 let act: BigNum = 2f64.pow(200_000);
174 let exp = BigNum::new(1, 200_000);
175 let (min, max) = if act > exp { (exp, act) } else { (act, exp) };
176
177 assert!(
178 min.fuzzy_eq(max, u64::MAX / 1_000_000),
179 "{:?} {:?}",
180 min,
181 max
182 );
183
184 let act: BigNum = 2f64.pow(2_000_000);
185 let exp = BigNum::new(1, 2_000_000);
186 let (min, max) = if act > exp { (exp, act) } else { (act, exp) };
187
188 assert!(
189 min.fuzzy_eq(max, u64::MAX / 1_000_000),
190 "{:?} {:?}",
191 min,
192 max
193 );
194
195 let act: BigNum = 2f64.pow(2_000_000_000);
196 let exp = BigNum::new(1, 2_000_000_000);
197 let (min, max) = if act > exp { (exp, act) } else { (act, exp) };
198
199 assert!(
201 max.exp as f64 / (max.exp - min.exp) as f64 > 10_000.,
202 "{} {}",
203 min.exp,
204 max.exp
205 );
206 }
207}