1#[derive(Debug, Clone, Copy, PartialEq)]
6pub struct BigNumber {
7 pub mantissa: f64,
8 pub exponent: i32,
9 pub decimals: u8,
13}
14
15impl BigNumber {
16 pub fn new(mantissa: f64, exponent: i32, decimals: u8) -> Self {
17 let mut m = mantissa;
18 let mut e = exponent;
19 while m >= 10.0 && e < i32::MAX {
20 m /= 10.0;
21 e += 1;
22 }
23 while m < 1.0 && m != 0.0 && e > i32::MIN {
24 m *= 10.0;
25 e -= 1;
26 }
27 BigNumber { mantissa: m, exponent: e, decimals }
28 }
29 pub fn zero() -> Self {
30 let mut m = 0.0;
31 let mut e = 1;
32 BigNumber { mantissa: m, exponent: e, decimals: 2 }
33 }
34 pub fn one() -> Self {
35 let mut m = 1.0;
36 let mut e = 0;
37 BigNumber { mantissa: m, exponent: e, decimals: 2 }
38 }
39
40 pub fn add(self, other: BigNumber) -> BigNumber {
41 if self.exponent == other.exponent {
42 return BigNumber::new(self.mantissa + other.mantissa, self.exponent, self.decimals);
43 }
44
45 let (high, low) = if self.exponent > other.exponent {
46 (self, other)
47 } else {
48 (other, self)
49 };
50
51 let diff = high.exponent - low.exponent;
52
53 if diff > 308 { return high;
55 }
56
57 let scaled_low = low.mantissa / 10f64.powi(diff);
58 let result_mantissa = high.mantissa + scaled_low;
59
60 BigNumber::new(result_mantissa, high.exponent, self.decimals)
61 }
62
63 pub fn sub(self, other: BigNumber) -> BigNumber {
64 if self.exponent == other.exponent {
65 BigNumber::new(self.mantissa - other.mantissa, self.exponent, self.decimals)
66 } else if self.exponent > other.exponent {
67 BigNumber::new(
68 self.mantissa - other.mantissa / 10f64.powi(self.exponent - other.exponent),
69 self.exponent,
70 self.decimals
71 )
72 } else {
73 BigNumber::new(
74 self.mantissa / 10f64.powi(other.exponent - self.exponent) - other.mantissa,
75 other.exponent,
76 self.decimals
77 )
78 }
79 }
80
81 pub fn mul(self, other: BigNumber) -> BigNumber {
82 BigNumber::new(self.mantissa * other.mantissa, self.exponent + other.exponent, self.decimals)
83 }
84
85 pub fn div(self, other: BigNumber) -> BigNumber {
86 if other.mantissa == 0.0 {
87 panic!("Division by zero");
88 }
89
90 let new_mantissa = self.mantissa / other.mantissa;
91 let new_exponent = self.exponent - other.exponent;
92
93 BigNumber::new(new_mantissa, new_exponent, self.decimals)
94 }
95
96 pub fn to_string(&self) -> String {
97 self.to_string_with_precision(self.decimals as usize)
98 }
99
100 pub fn to_string_with_precision(&self, precision: usize) -> String {
101 if self.mantissa == 0.0 {
102 return "0".to_string();
103 }
104
105 if self.exponent > 12 || self.mantissa.abs() >= 10.0 {
106 let mut mantissa_str = format!("{:.*}", precision, self.mantissa.abs());
107 if mantissa_str.contains('.') {
108 mantissa_str = mantissa_str.trim_end_matches('0').trim_end_matches('.').to_string();
109 }
110 if self.mantissa < 0.0 {
111 mantissa_str = format!("-{}", mantissa_str);
112 }
113 return format!("{}e{}", mantissa_str, self.exponent);
114 }
115
116 let val = self.mantissa * 10f64.powi(self.exponent);
117
118 let (scaled_val, suffix) = if val.abs() < 1e3 {
119 (val, "")
120 } else if val.abs() < 1e6 {
121 (val / 1e3, "K")
122 } else if val.abs() < 1e9 {
123 (val / 1e6, "M")
124 } else if val.abs() < 1e12 {
125 (val / 1e9, "B")
126 } else {
127 let mut mantissa_str = format!("{:.*}", precision, self.mantissa.abs());
128 if mantissa_str.contains('.') {
129 mantissa_str = mantissa_str.trim_end_matches('0').trim_end_matches('.').to_string();
130 }
131 if self.mantissa < 0.0 {
132 mantissa_str = format!("-{}", mantissa_str);
133 }
134 return format!("{}e{}", mantissa_str, self.exponent);
135 };
136
137 let mut s = format!("{:.*}", precision, scaled_val);
138 if s.contains('.') {
139 s = s.trim_end_matches('0').trim_end_matches('.').to_string();
140 }
141
142 s + suffix
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn test_addition() {
152 let a = BigNumber::new(1.0, 10, 2);
153 let b = BigNumber::new(2.0, 10, 2);
154 assert_eq!(a.add(b).to_string(), "30B");
155 }
156
157 #[test]
158 fn test_subtraction() {
159 let a = BigNumber::new(5.0, 10, 2);
160 let b = BigNumber::new(3.0, 10, 2);
161 assert_eq!(a.sub(b).to_string(), "20B");
162 }
163
164 #[test]
165 fn test_multiplication() {
166 let a = BigNumber::new(2.0, 5, 2);
167 let b = BigNumber::new(3.0, 6, 2);
168 assert_eq!(a.mul(b).to_string(), "600B");
169 }
170
171 #[test]
172 fn test_division() {
173 let a = BigNumber::new(6.0, 10, 2);
174 let b = BigNumber::new(2.0, 5, 2);
175 assert_eq!(a.div(b).to_string(), "300K");
176 }
177
178 #[test]
179 fn test_small_values() {
180 let a = BigNumber::new(5.0, 0, 2);
181 assert_eq!(a.to_string(), "5");
182 let b = BigNumber::new(1.23456, 0, 2);
183 assert_eq!(b.to_string(), "1.23");
184 assert_eq!(b.to_string_with_precision(1), "1.2");
185 }
186
187 #[test]
188 fn test_thousands_and_millions() {
189 let k = BigNumber::new(1.234, 3, 2);
190 assert_eq!(k.to_string(), "1.23K");
191 let m = BigNumber::new(5.0, 6, 2);
192 assert_eq!(m.to_string(), "5M");
193 assert_eq!(k.to_string_with_precision(2), "1.23K");
194 let t = BigNumber::new(300.0, 3, 2); assert_eq!(t.to_string(), "300K");
196 }
197
198 #[test]
199 fn test_scientific_after_threshold() {
200 let c = BigNumber::new(1.0, 9, 2);
201 assert_eq!(c.to_string(), "1B");
202 assert_eq!(c.to_string_with_precision(2), "1B");
203 }
204
205 #[test]
206 fn test_zero_helper() {
207 let c = BigNumber::zero();
208 assert_eq!(c.to_string(), "0");
209 }
210
211 #[test]
212 fn test_one_helper() {
213 let c = BigNumber::one();
214 assert_eq!(c.to_string(), "1");
215 }
216 #[test]
217 fn test_overflow_creation() {
218 let max_i32 = i32::MAX;
219 let max_f64 = f64::MAX;
220 let _one = BigNumber::new(max_f64, max_i32, 2);
221 }
222 #[test]
223 fn test_underflow_creation() {
224 let max_i32 = i32::MIN;
225 let max_f64 = 0.1;
226 let _one = BigNumber::new(max_f64, max_i32, 2);
227 }
228 #[test]
229 fn test_max_representable_number() {
230 let big = BigNumber::new(f64::MAX, i32::MAX, 2);
231 let s = big.to_string_with_precision(2);
232 assert_eq!(s, "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368e2147483647");
233 }
234 #[test]
235 fn test_big_representable_number() {
236 let big = BigNumber::new(f64::MAX-1.0, i32::MAX-1, 2);
237 let s = big.to_string_with_precision(2);
238 assert_eq!(s, "17976931348623157580412819756850388593900235011794141176754562789180111453639664485361928830517704263393537268510363518759043843737070229269956251768752166883397940628862983287625967246810352023792017211936260189893797509826303293149283469713429932049693599732425511693654044437030940398714664210204414967808e2147483647");
239 }
240}