mathhook_core/core/number/
arithmetic.rs1use super::types::Number;
8use crate::error::MathError;
9use num_bigint::BigInt;
10use num_rational::BigRational;
11use num_traits::ToPrimitive;
12use std::ops::{Add, Div, Mul, Neg, Sub};
13
14impl Add for Number {
27 type Output = Result<Number, MathError>;
28
29 fn add(self, other: Number) -> Result<Number, MathError> {
30 match (self, other) {
31 (Number::Integer(a), Number::Integer(b)) => match a.checked_add(b) {
32 Some(result) => Ok(Number::Integer(result)),
33 None => Ok(Number::BigInteger(Box::new(
34 BigInt::from(a) + BigInt::from(b),
35 ))),
36 },
37
38 (Number::BigInteger(a), Number::BigInteger(b)) => {
39 Ok(Number::BigInteger(Box::new(*a + *b)))
40 }
41
42 (Number::Integer(i), Number::BigInteger(bi))
43 | (Number::BigInteger(bi), Number::Integer(i)) => {
44 Ok(Number::BigInteger(Box::new(*bi + BigInt::from(i))))
45 }
46
47 (Number::Rational(a), Number::Rational(b)) => Ok(Number::Rational(Box::new(*a + *b))),
48
49 (Number::Integer(i), Number::Rational(r))
50 | (Number::Rational(r), Number::Integer(i)) => {
51 let i_rational = BigRational::from(BigInt::from(i));
52 Ok(Number::Rational(Box::new(i_rational + *r)))
53 }
54
55 (Number::BigInteger(bi), Number::Rational(r))
56 | (Number::Rational(r), Number::BigInteger(bi)) => {
57 let bi_rational = BigRational::from(*bi);
58 Ok(Number::Rational(Box::new(bi_rational + *r)))
59 }
60
61 (Number::Float(a), Number::Float(b)) => {
62 let result = a + b;
63 if result.is_infinite() || result.is_nan() {
64 Err(MathError::NumericOverflow {
65 operation: "float addition".to_owned(),
66 })
67 } else {
68 Ok(Number::Float(result))
69 }
70 }
71
72 (Number::Integer(i), Number::Float(f)) | (Number::Float(f), Number::Integer(i)) => {
73 let result = i as f64 + f;
74 if result.is_infinite() || result.is_nan() {
75 Err(MathError::NumericOverflow {
76 operation: "integer-float addition".to_owned(),
77 })
78 } else {
79 Ok(Number::Float(result))
80 }
81 }
82
83 (Number::BigInteger(bi), Number::Float(f))
84 | (Number::Float(f), Number::BigInteger(bi)) => {
85 let bi_float = bi.to_f64().ok_or_else(|| MathError::NumericOverflow {
86 operation: "BigInteger to float conversion".to_owned(),
87 })?;
88 let result = bi_float + f;
89 if result.is_infinite() || result.is_nan() {
90 Err(MathError::NumericOverflow {
91 operation: "BigInteger-float addition".to_owned(),
92 })
93 } else {
94 Ok(Number::Float(result))
95 }
96 }
97
98 (Number::Rational(r), Number::Float(f)) | (Number::Float(f), Number::Rational(r)) => {
99 let numer_float = r
100 .numer()
101 .to_f64()
102 .ok_or_else(|| MathError::NumericOverflow {
103 operation: "Rational numerator to float conversion".to_owned(),
104 })?;
105 let denom_float = r
106 .denom()
107 .to_f64()
108 .ok_or_else(|| MathError::NumericOverflow {
109 operation: "Rational denominator to float conversion".to_owned(),
110 })?;
111 let r_float = numer_float / denom_float;
112 let result = r_float + f;
113 if result.is_infinite() || result.is_nan() {
114 Err(MathError::NumericOverflow {
115 operation: "Rational-float addition".to_owned(),
116 })
117 } else {
118 Ok(Number::Float(result))
119 }
120 }
121 }
122 }
123}
124
125impl Sub for Number {
138 type Output = Result<Number, MathError>;
139
140 fn sub(self, other: Number) -> Result<Number, MathError> {
141 match (self, other) {
142 (Number::Integer(a), Number::Integer(b)) => match a.checked_sub(b) {
143 Some(result) => Ok(Number::Integer(result)),
144 None => Ok(Number::BigInteger(Box::new(
145 BigInt::from(a) - BigInt::from(b),
146 ))),
147 },
148
149 (Number::BigInteger(a), Number::BigInteger(b)) => {
150 Ok(Number::BigInteger(Box::new(*a - *b)))
151 }
152
153 (Number::Integer(i), Number::BigInteger(bi)) => {
154 Ok(Number::BigInteger(Box::new(BigInt::from(i) - *bi)))
155 }
156
157 (Number::BigInteger(bi), Number::Integer(i)) => {
158 Ok(Number::BigInteger(Box::new(*bi - BigInt::from(i))))
159 }
160
161 (Number::Rational(a), Number::Rational(b)) => Ok(Number::Rational(Box::new(*a - *b))),
162
163 (Number::Integer(i), Number::Rational(r)) => {
164 let i_rational = BigRational::from(BigInt::from(i));
165 Ok(Number::Rational(Box::new(i_rational - *r)))
166 }
167
168 (Number::Rational(r), Number::Integer(i)) => {
169 let i_rational = BigRational::from(BigInt::from(i));
170 Ok(Number::Rational(Box::new(*r - i_rational)))
171 }
172
173 (Number::BigInteger(bi), Number::Rational(r)) => {
174 let bi_rational = BigRational::from(*bi);
175 Ok(Number::Rational(Box::new(bi_rational - *r)))
176 }
177
178 (Number::Rational(r), Number::BigInteger(bi)) => {
179 let bi_rational = BigRational::from(*bi);
180 Ok(Number::Rational(Box::new(*r - bi_rational)))
181 }
182
183 (Number::Float(a), Number::Float(b)) => {
184 let result = a - b;
185 if result.is_infinite() || result.is_nan() {
186 Err(MathError::NumericOverflow {
187 operation: "float subtraction".to_owned(),
188 })
189 } else {
190 Ok(Number::Float(result))
191 }
192 }
193
194 (Number::Integer(i), Number::Float(f)) => {
195 let result = i as f64 - f;
196 if result.is_infinite() || result.is_nan() {
197 Err(MathError::NumericOverflow {
198 operation: "integer-float subtraction".to_owned(),
199 })
200 } else {
201 Ok(Number::Float(result))
202 }
203 }
204
205 (Number::Float(f), Number::Integer(i)) => {
206 let result = f - i as f64;
207 if result.is_infinite() || result.is_nan() {
208 Err(MathError::NumericOverflow {
209 operation: "float-integer subtraction".to_owned(),
210 })
211 } else {
212 Ok(Number::Float(result))
213 }
214 }
215
216 (Number::BigInteger(bi), Number::Float(f)) => {
217 let bi_float = bi.to_f64().ok_or_else(|| MathError::NumericOverflow {
218 operation: "BigInteger to float conversion".to_owned(),
219 })?;
220 let result = bi_float - f;
221 if result.is_infinite() || result.is_nan() {
222 Err(MathError::NumericOverflow {
223 operation: "BigInteger-float subtraction".to_owned(),
224 })
225 } else {
226 Ok(Number::Float(result))
227 }
228 }
229
230 (Number::Float(f), Number::BigInteger(bi)) => {
231 let bi_float = bi.to_f64().ok_or_else(|| MathError::NumericOverflow {
232 operation: "BigInteger to float conversion".to_owned(),
233 })?;
234 let result = f - bi_float;
235 if result.is_infinite() || result.is_nan() {
236 Err(MathError::NumericOverflow {
237 operation: "float-BigInteger subtraction".to_owned(),
238 })
239 } else {
240 Ok(Number::Float(result))
241 }
242 }
243
244 (Number::Rational(r), Number::Float(f)) => {
245 let numer_float = r
246 .numer()
247 .to_f64()
248 .ok_or_else(|| MathError::NumericOverflow {
249 operation: "Rational numerator to float conversion".to_owned(),
250 })?;
251 let denom_float = r
252 .denom()
253 .to_f64()
254 .ok_or_else(|| MathError::NumericOverflow {
255 operation: "Rational denominator to float conversion".to_owned(),
256 })?;
257 let r_float = numer_float / denom_float;
258 let result = r_float - f;
259 if result.is_infinite() || result.is_nan() {
260 Err(MathError::NumericOverflow {
261 operation: "Rational-float subtraction".to_owned(),
262 })
263 } else {
264 Ok(Number::Float(result))
265 }
266 }
267
268 (Number::Float(f), Number::Rational(r)) => {
269 let numer_float = r
270 .numer()
271 .to_f64()
272 .ok_or_else(|| MathError::NumericOverflow {
273 operation: "Rational numerator to float conversion".to_owned(),
274 })?;
275 let denom_float = r
276 .denom()
277 .to_f64()
278 .ok_or_else(|| MathError::NumericOverflow {
279 operation: "Rational denominator to float conversion".to_owned(),
280 })?;
281 let r_float = numer_float / denom_float;
282 let result = f - r_float;
283 if result.is_infinite() || result.is_nan() {
284 Err(MathError::NumericOverflow {
285 operation: "float-Rational subtraction".to_owned(),
286 })
287 } else {
288 Ok(Number::Float(result))
289 }
290 }
291 }
292 }
293}
294
295impl Mul for Number {
308 type Output = Result<Number, MathError>;
309
310 fn mul(self, other: Number) -> Result<Number, MathError> {
311 match (self, other) {
312 (Number::Integer(a), Number::Integer(b)) => match a.checked_mul(b) {
313 Some(result) => Ok(Number::Integer(result)),
314 None => Ok(Number::BigInteger(Box::new(
315 BigInt::from(a) * BigInt::from(b),
316 ))),
317 },
318
319 (Number::BigInteger(a), Number::BigInteger(b)) => {
320 Ok(Number::BigInteger(Box::new(*a * *b)))
321 }
322
323 (Number::Integer(i), Number::BigInteger(bi))
324 | (Number::BigInteger(bi), Number::Integer(i)) => {
325 Ok(Number::BigInteger(Box::new(*bi * BigInt::from(i))))
326 }
327
328 (Number::Rational(a), Number::Rational(b)) => Ok(Number::Rational(Box::new(*a * *b))),
329
330 (Number::Integer(i), Number::Rational(r))
331 | (Number::Rational(r), Number::Integer(i)) => {
332 let i_rational = BigRational::from(BigInt::from(i));
333 Ok(Number::Rational(Box::new(i_rational * *r)))
334 }
335
336 (Number::BigInteger(bi), Number::Rational(r))
337 | (Number::Rational(r), Number::BigInteger(bi)) => {
338 let bi_rational = BigRational::from(*bi);
339 Ok(Number::Rational(Box::new(bi_rational * *r)))
340 }
341
342 (Number::Float(a), Number::Float(b)) => {
343 let result = a * b;
344 if result.is_infinite() || result.is_nan() {
345 Err(MathError::NumericOverflow {
346 operation: "float multiplication".to_owned(),
347 })
348 } else {
349 Ok(Number::Float(result))
350 }
351 }
352
353 (Number::Integer(i), Number::Float(f)) | (Number::Float(f), Number::Integer(i)) => {
354 let result = i as f64 * f;
355 if result.is_infinite() || result.is_nan() {
356 Err(MathError::NumericOverflow {
357 operation: "integer-float multiplication".to_owned(),
358 })
359 } else {
360 Ok(Number::Float(result))
361 }
362 }
363
364 (Number::BigInteger(bi), Number::Float(f))
365 | (Number::Float(f), Number::BigInteger(bi)) => {
366 let bi_float = bi.to_f64().ok_or_else(|| MathError::NumericOverflow {
367 operation: "BigInteger to float conversion".to_owned(),
368 })?;
369 let result = bi_float * f;
370 if result.is_infinite() || result.is_nan() {
371 Err(MathError::NumericOverflow {
372 operation: "BigInteger-float multiplication".to_owned(),
373 })
374 } else {
375 Ok(Number::Float(result))
376 }
377 }
378
379 (Number::Rational(r), Number::Float(f)) | (Number::Float(f), Number::Rational(r)) => {
380 let numer_float = r
381 .numer()
382 .to_f64()
383 .ok_or_else(|| MathError::NumericOverflow {
384 operation: "Rational numerator to float conversion".to_owned(),
385 })?;
386 let denom_float = r
387 .denom()
388 .to_f64()
389 .ok_or_else(|| MathError::NumericOverflow {
390 operation: "Rational denominator to float conversion".to_owned(),
391 })?;
392 let r_float = numer_float / denom_float;
393 let result = r_float * f;
394 if result.is_infinite() || result.is_nan() {
395 Err(MathError::NumericOverflow {
396 operation: "Rational-float multiplication".to_owned(),
397 })
398 } else {
399 Ok(Number::Float(result))
400 }
401 }
402 }
403 }
404}
405
406impl Div for Number {
419 type Output = Result<Number, MathError>;
420
421 fn div(self, other: Number) -> Result<Number, MathError> {
422 if other.is_zero() {
423 return Err(MathError::DivisionByZero);
424 }
425
426 match (self, other) {
427 (Number::Integer(a), Number::Integer(b)) => {
428 if a % b == 0 {
429 Ok(Number::Integer(a / b))
430 } else {
431 Ok(Number::Rational(Box::new(BigRational::new(
432 BigInt::from(a),
433 BigInt::from(b),
434 ))))
435 }
436 }
437
438 (Number::BigInteger(a), Number::BigInteger(b)) => {
439 if (*a).clone() % (*b).clone() == BigInt::from(0) {
440 Ok(Number::BigInteger(Box::new(*a / *b)))
441 } else {
442 Ok(Number::Rational(Box::new(BigRational::new(*a, *b))))
443 }
444 }
445
446 (Number::Integer(i), Number::BigInteger(bi)) => Ok(Number::Rational(Box::new(
447 BigRational::new(BigInt::from(i), *bi),
448 ))),
449
450 (Number::BigInteger(bi), Number::Integer(i)) => Ok(Number::Rational(Box::new(
451 BigRational::new(*bi, BigInt::from(i)),
452 ))),
453
454 (Number::Rational(a), Number::Rational(b)) => Ok(Number::Rational(Box::new(*a / *b))),
455
456 (Number::Integer(i), Number::Rational(r)) => {
457 let i_rational = BigRational::from(BigInt::from(i));
458 Ok(Number::Rational(Box::new(i_rational / *r)))
459 }
460
461 (Number::Rational(r), Number::Integer(i)) => {
462 let i_rational = BigRational::from(BigInt::from(i));
463 Ok(Number::Rational(Box::new(*r / i_rational)))
464 }
465
466 (Number::BigInteger(bi), Number::Rational(r)) => {
467 let bi_rational = BigRational::from(*bi);
468 Ok(Number::Rational(Box::new(bi_rational / *r)))
469 }
470
471 (Number::Rational(r), Number::BigInteger(bi)) => {
472 let bi_rational = BigRational::from(*bi);
473 Ok(Number::Rational(Box::new(*r / bi_rational)))
474 }
475
476 (Number::Float(a), Number::Float(b)) => {
477 let result = a / b;
478 if result.is_infinite() || result.is_nan() {
479 Err(MathError::NumericOverflow {
480 operation: "float division".to_owned(),
481 })
482 } else {
483 Ok(Number::Float(result))
484 }
485 }
486
487 (Number::Integer(i), Number::Float(f)) => {
488 let result = i as f64 / f;
489 if result.is_infinite() || result.is_nan() {
490 Err(MathError::NumericOverflow {
491 operation: "integer-float division".to_owned(),
492 })
493 } else {
494 Ok(Number::Float(result))
495 }
496 }
497
498 (Number::Float(f), Number::Integer(i)) => {
499 let result = f / i as f64;
500 if result.is_infinite() || result.is_nan() {
501 Err(MathError::NumericOverflow {
502 operation: "float-integer division".to_owned(),
503 })
504 } else {
505 Ok(Number::Float(result))
506 }
507 }
508
509 (Number::BigInteger(bi), Number::Float(f)) => {
510 let bi_float = bi.to_f64().ok_or_else(|| MathError::NumericOverflow {
511 operation: "BigInteger to float conversion".to_owned(),
512 })?;
513 let result = bi_float / f;
514 if result.is_infinite() || result.is_nan() {
515 Err(MathError::NumericOverflow {
516 operation: "BigInteger-float division".to_owned(),
517 })
518 } else {
519 Ok(Number::Float(result))
520 }
521 }
522
523 (Number::Float(f), Number::BigInteger(bi)) => {
524 let bi_float = bi.to_f64().ok_or_else(|| MathError::NumericOverflow {
525 operation: "BigInteger to float conversion".to_owned(),
526 })?;
527 let result = f / bi_float;
528 if result.is_infinite() || result.is_nan() {
529 Err(MathError::NumericOverflow {
530 operation: "float-BigInteger division".to_owned(),
531 })
532 } else {
533 Ok(Number::Float(result))
534 }
535 }
536
537 (Number::Rational(r), Number::Float(f)) => {
538 let numer_float = r
539 .numer()
540 .to_f64()
541 .ok_or_else(|| MathError::NumericOverflow {
542 operation: "Rational numerator to float conversion".to_owned(),
543 })?;
544 let denom_float = r
545 .denom()
546 .to_f64()
547 .ok_or_else(|| MathError::NumericOverflow {
548 operation: "Rational denominator to float conversion".to_owned(),
549 })?;
550 let r_float = numer_float / denom_float;
551 let result = r_float / f;
552 if result.is_infinite() || result.is_nan() {
553 Err(MathError::NumericOverflow {
554 operation: "Rational-float division".to_owned(),
555 })
556 } else {
557 Ok(Number::Float(result))
558 }
559 }
560
561 (Number::Float(f), Number::Rational(r)) => {
562 let numer_float = r
563 .numer()
564 .to_f64()
565 .ok_or_else(|| MathError::NumericOverflow {
566 operation: "Rational numerator to float conversion".to_owned(),
567 })?;
568 let denom_float = r
569 .denom()
570 .to_f64()
571 .ok_or_else(|| MathError::NumericOverflow {
572 operation: "Rational denominator to float conversion".to_owned(),
573 })?;
574 let r_float = numer_float / denom_float;
575 let result = f / r_float;
576 if result.is_infinite() || result.is_nan() {
577 Err(MathError::NumericOverflow {
578 operation: "float-Rational division".to_owned(),
579 })
580 } else {
581 Ok(Number::Float(result))
582 }
583 }
584 }
585 }
586}
587
588impl Neg for Number {
600 type Output = Result<Number, MathError>;
601
602 fn neg(self) -> Result<Number, MathError> {
603 match self {
604 Number::Integer(i) => match i.checked_neg() {
605 Some(result) => Ok(Number::Integer(result)),
606 None => Ok(Number::BigInteger(Box::new(-BigInt::from(i)))),
607 },
608
609 Number::BigInteger(bi) => Ok(Number::BigInteger(Box::new(-*bi))),
610
611 Number::Float(f) => Ok(Number::Float(-f)),
612
613 Number::Rational(r) => Ok(Number::Rational(Box::new(-*r))),
614 }
615 }
616}