1use crate::NonZeroUbig;
3use crate::rational::{Rational16, Rational32, Rational64, Rational8};
4use crate::rational::big::Big;
5use crate::sign::Negateable;
6use crate::sign::Sign;
7use crate::Ubig;
8
9macro_rules! define_interations {
10 ($small:ident, $module_name:ident) => {
11 mod $module_name {
12 use super::*;
13
14 mod creation {
15 use super::*;
16
17 impl<const S: usize> From<$small> for Big<S> {
18 #[inline]
19 fn from(value: $small) -> Self {
20 Self {
21 sign: value.sign,
22 numerator: Ubig::new(value.numerator as usize),
23 denominator: unsafe {
24 NonZeroUbig::new_unchecked(value.denominator as usize)
26 },
27 }
28 }
29 }
30
31 impl<const S: usize> From<&$small> for Big<S> {
32 #[inline]
33 fn from(value: &$small) -> Self {
34 Self {
35 sign: value.sign,
36 numerator: Ubig::new(value.numerator as usize),
37 denominator: unsafe {
38 NonZeroUbig::new_unchecked(value.denominator as usize)
40 },
41 }
42 }
43 }
44 }
45
46 mod compare {
47 use super::*;
48
49 impl<const S: usize> PartialEq<$small> for Big<S> {
50 #[inline]
51 fn eq(&self, other: &$small) -> bool {
52 *self.denominator.first() == other.denominator as usize &&
55 match self.sign {
56 Sign::Zero => other.sign == Sign::Zero,
57 Sign::Positive | Sign::Negative => {
58 self.sign == other.sign &&
59 self.numerator[0] == other.numerator as usize &&
60 self.numerator.len() == 1 &&
61 self.denominator.len() == 1
62 }
63 }
64 }
65 }
66 }
67
68 mod field {
69 use super::*;
70 use crate::sign::Sign;
71
72 mod add {
73 use super::*;
74 use std::ops::{Add, AddAssign};
75 use crate::rational::big::ops::building_blocks::{add_small, sub_small, SignChange};
76
77 impl<const S: usize> Add<$small> for Big<S> {
78 type Output = Self;
79
80 #[inline]
81 fn add(mut self, rhs: $small) -> Self::Output {
82 AddAssign::add_assign(&mut self, &rhs);
83 self
84 }
85 }
86
87 impl<const S: usize> Add<&$small> for Big<S> {
88 type Output = Self;
89
90 #[inline]
91 fn add(mut self, rhs: &$small) -> Self::Output {
92 AddAssign::add_assign(&mut self, rhs);
93 self
94 }
95 }
96
97 impl<const S: usize> Add<Option<&$small>> for Big<S> {
98 type Output = Self;
99
100 #[inline]
101 fn add(self, rhs: Option<&$small>) -> Self::Output {
102 match rhs {
103 None => self,
104 Some(rhs) => Add::add(self, rhs),
105 }
106 }
107 }
108
109 impl<const S: usize> Add<&$small> for &Big<S> {
110 type Output = Big<S>;
111
112 #[inline]
113 fn add(self, rhs: &$small) -> Self::Output {
114 let mut cloned = self.clone();
116 AddAssign::add_assign(&mut cloned, rhs);
117 cloned
118 }
119 }
120
121 impl<const S: usize> Add<Option<&$small>> for &Big<S> {
122 type Output = Big<S>;
123
124 #[inline]
125 fn add(self, rhs: Option<&$small>) -> Self::Output {
126 let copy = self.clone();
128 match rhs {
129 None => copy,
130 Some(rhs) => Add::add(copy, rhs),
131 }
132 }
133 }
134
135 impl<const S: usize> AddAssign<$small> for Big<S> {
136 #[inline]
137 fn add_assign(&mut self, rhs: $small) {
138 AddAssign::add_assign(self, &rhs);
139 }
140 }
141
142 impl<const S: usize> AddAssign<&$small> for Big<S> {
143 #[inline]
144 fn add_assign(&mut self, rhs: &$small) {
145 match (self.sign, rhs.sign) {
146 (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
147 unsafe {
148 add_small(
150 self.numerator.inner_mut(),
151 self.denominator.inner_mut(),
152 rhs.numerator as usize,
153 rhs.denominator as usize,
154 );
155 }
156 },
157 (Sign::Negative, Sign::Positive) | (Sign::Positive, Sign::Negative) => {
158 unsafe {
159 let sign_change = sub_small(
161 self.numerator.inner_mut(),
162 self.denominator.inner_mut(),
163 rhs.numerator as usize,
164 rhs.denominator as usize,
165 );
166 match sign_change {
167 SignChange::None => {}
168 SignChange::Flip => self.sign.negate(),
169 SignChange::Zero => self.sign = Sign::Zero,
170 }
171 }
172 }
173 (_, Sign::Zero) => {}
174 (Sign::Zero, _) => {
175 self.sign = rhs.sign;
176 debug_assert_eq!(self.numerator.len(), 0);
177 unsafe {
178 self.numerator.inner_mut().push(rhs.numerator as usize);
180 }
181 debug_assert_eq!(self.denominator.len(), 1);
182 debug_assert_eq!(self.denominator[0], 1);
183 unsafe {
184 *self.denominator.first_mut() = rhs.denominator as usize;
186 }
187 }
188 }
189 }
190 }
191 }
192
193 mod sub {
194 use super::*;
195 use crate::rational::big::ops::building_blocks::{add_small, sub_small, SignChange};
196 use std::ops::{Sub, SubAssign};
197
198 impl<const S: usize> Sub<$small> for Big<S> {
199 type Output = Self;
200
201 #[inline]
202 fn sub(mut self, rhs: $small) -> Self::Output {
203 SubAssign::sub_assign(&mut self, &rhs);
204 self
205 }
206 }
207
208 impl<const S: usize> Sub<&$small> for Big<S> {
209 type Output = Self;
210
211 #[inline]
212 fn sub(mut self, rhs: &$small) -> Self::Output {
213 SubAssign::sub_assign(&mut self, rhs);
214 self
215 }
216 }
217
218 impl<const S: usize> Sub<Option<&$small>> for Big<S> {
219 type Output = Self;
220
221 #[inline]
222 fn sub(self, rhs: Option<&$small>) -> Self::Output {
223 match rhs {
224 None => self,
225 Some(rhs) => Sub::sub(self, rhs),
226 }
227 }
228 }
229
230 impl<const S: usize> Sub<&$small> for &Big<S> {
231 type Output = Big<S>;
232
233 #[inline]
234 fn sub(self, rhs: &$small) -> Self::Output {
235 let mut cloned = self.clone();
237 SubAssign::sub_assign(&mut cloned, rhs);
238 cloned
239 }
240 }
241
242 impl<const S: usize> Sub<Option<&$small>> for &Big<S> {
243 type Output = Big<S>;
244
245 #[inline]
246 fn sub(self, rhs: Option<&$small>) -> Self::Output {
247 let copy = self.clone();
249 match rhs {
250 None => copy,
251 Some(rhs) => Sub::sub(copy, rhs),
252 }
253 }
254 }
255
256 impl<const S: usize> SubAssign<$small> for Big<S> {
257 #[inline]
258 fn sub_assign(&mut self, rhs: $small) {
259 SubAssign::sub_assign(self, &rhs);
260 }
261 }
262
263 impl<const S: usize> SubAssign<&$small> for Big<S> {
264 #[inline]
265 fn sub_assign(&mut self, rhs: &$small) {
266 match (self.sign, rhs.sign) {
267 (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
268 unsafe {
269 let sign_change = sub_small(
271 self.numerator.inner_mut(),
272 self.denominator.inner_mut(),
273 rhs.numerator as usize,
274 rhs.denominator as usize,
275 );
276 match sign_change {
277 SignChange::None => {}
278 SignChange::Flip => self.sign.negate(),
279 SignChange::Zero => self.sign = Sign::Zero,
280 }
281 }
282 }
283 (Sign::Negative, Sign::Positive) | (Sign::Positive, Sign::Negative) => {
284 unsafe {
285 add_small(
287 self.numerator.inner_mut(),
288 self.denominator.inner_mut(),
289 rhs.numerator as usize,
290 rhs.denominator as usize,
291 );
292 }
293 }
294 (_, Sign::Zero) => {}
295 (Sign::Zero, _) => {
296 self.sign = -rhs.sign;
297 debug_assert_eq!(self.numerator.len(), 0);
298 unsafe {
299 self.numerator.inner_mut().push(rhs.numerator as usize)
301 };
302 debug_assert_eq!(self.denominator.len(), 1);
303 debug_assert_eq!(self.denominator[0], 1);
304 unsafe {
305 *self.denominator.first_mut() = rhs.denominator as usize;
307 }
308 }
309 }
310 }
311 }
312 }
313
314 mod mul {
315 use super::*;
316 use std::ops::{Mul, MulAssign};
317 use crate::rational::big::ops::building_blocks::mul_small;
318
319 impl<const S: usize> Mul<$small> for Big<S> {
320 type Output = Self;
321
322 #[inline]
323 fn mul(self, rhs: $small) -> Self::Output {
324 Mul::mul(self, &rhs)
325 }
326 }
327
328 impl<const S: usize> Mul<&$small> for Big<S> {
329 type Output = Self;
330
331 #[inline]
332 fn mul(mut self, rhs: &$small) -> Self::Output {
333 MulAssign::mul_assign(&mut self, rhs);
334 self
335 }
336 }
337
338 impl<const S: usize> Mul<&$small> for &Big<S> {
339 type Output = Big<S>;
340
341 #[inline]
342 fn mul(self, rhs: &$small) -> Self::Output {
343 self.clone() * rhs
345 }
346 }
347
348 impl<const S: usize> Mul<Option<&$small>> for Big<S> {
349 type Output = Big<S>;
350
351 #[inline]
352 fn mul(mut self, rhs: Option<&$small>) -> Self::Output {
353 match rhs {
354 None => {
355 <Self as num_traits::Zero>::set_zero(&mut self);
356 self
357 },
358 Some(rhs) => Mul::mul(self, rhs),
359 }
360 }
361 }
362
363 impl<const S: usize> Mul<Option<&$small>> for &Big<S> {
364 type Output = Big<S>;
365
366 #[inline]
367 fn mul(self, rhs: Option<&$small>) -> Self::Output {
368 match rhs {
369 None => <Self::Output as num_traits::Zero>::zero(),
370 Some(rhs) => Mul::mul(self, rhs),
371 }
372 }
373 }
374
375 impl<const S: usize> MulAssign<$small> for Big<S> {
376 #[inline]
377 fn mul_assign(&mut self, rhs: $small) {
378 MulAssign::mul_assign(self, &rhs);
379 }
380 }
381
382 impl<const S: usize> MulAssign<&$small> for Big<S> {
383 #[inline]
384 fn mul_assign(&mut self, rhs: &$small) {
385 match (self.sign, rhs.sign) {
386 (Sign::Positive | Sign::Negative, Sign::Positive | Sign::Negative) => {
387 self.sign *= rhs.sign;
388 unsafe {
389 mul_small(
390 self.numerator.inner_mut(),
391 self.denominator.inner_mut(),
392 rhs.numerator as usize,
393 rhs.denominator as usize,
394 )
395 }
396 }
397 (Sign::Positive | Sign::Negative, Sign::Zero) => {
398 <Self as num_traits::Zero>::set_zero(self);
399 }
400 (Sign::Zero, _) => {}
401 }
402 }
403 }
404 }
405
406 mod div {
407 use super::*;
408 use std::ops::{Div, DivAssign};
409 use crate::rational::big::ops::building_blocks::mul_small;
410
411 impl<const S: usize> Div<$small> for Big<S> {
412 type Output = Big<S>;
413
414 #[inline]
415 fn div(mut self, rhs: $small) -> Self::Output {
416 DivAssign::div_assign(&mut self, rhs);
417 self
418 }
419 }
420
421 impl<const S: usize> Div<&$small> for Big<S> {
422 type Output = Big<S>;
423
424 #[inline]
425 fn div(mut self, rhs: &$small) -> Self::Output {
426 DivAssign::div_assign(&mut self, rhs);
427 self
428 }
429 }
430
431 impl<const S: usize> DivAssign<$small> for Big<S> {
432 #[inline]
433 fn div_assign(&mut self, rhs: $small) {
434 DivAssign::div_assign(self, &rhs);
435 }
436 }
437
438 #[allow(clippy::suspicious_op_assign_impl)]
440 impl<const S: usize> DivAssign<&$small> for Big<S> {
441 #[inline]
442 fn div_assign(&mut self, rhs: &$small) {
443 match (self.sign, rhs.sign) {
444 (Sign::Positive | Sign::Negative, Sign::Positive | Sign::Negative) => {
445 self.sign *= rhs.sign;
446 unsafe {
447 mul_small(
448 self.numerator.inner_mut(),
449 self.denominator.inner_mut(),
450 rhs.denominator as usize,
451 rhs.numerator as usize,
452 );
453 }
454 }
455 (_, Sign::Zero) => panic!("attempt to divide by zero"),
456 (Sign::Zero, _) => {}
457 }
458 }
459 }
460 }
461 }
462 }
463 }
464}
465
466define_interations!(Rational8, rational8);
467define_interations!(Rational16, rational16);
468define_interations!(Rational32, rational32);
469define_interations!(Rational64, rational64);
470
471#[cfg(test)]
472mod test {
473 use num_traits::One;
474 use smallvec::smallvec;
475
476 use crate::{R16, R32, R64, R8, Rational64, RationalBig, RB, Sign, Ubig};
477 use crate::integer::big::NonZeroUbig;
478
479 #[test]
480 fn test_eq() {
481 assert_eq!(RB!(0), R64!(0));
482 assert_eq!(RB!(-2), R64!(-2));
483 assert_eq!(RB!(854984, 6868468468), R64!(854984, 6868468468));
484 assert_eq!(RB!(-989888, 4968468421), R64!(-989888, 4968468421));
485 assert_ne!(RB!(668468498646846546846546898997987_u128), R8!(1));
486 assert_ne!(RB!(668468498646846546846546898997987.4385484_f64), R8!(1, 2));
487 }
488
489 #[test]
490 fn test_add_sub() {
491 assert_eq!(RB!(0) + R8!(0), RB!(0));
492 assert_eq!(RB!(89) + R8!(1), RB!(90));
493 assert_eq!(RB!(89) - R16!(1), RB!(88));
494
495 assert_eq!(RB!(2, 3) + R16!(4, 9), RB!(10, 9));
496 assert_eq!(RB!(989, 141) + R8!(1, 141), RB!(990, 141));
497 assert_eq!(RB!(-84, 3) + R8!(1, 3), RB!(-83, 3));
498 assert_eq!(RB!(1, 2) + R8!(1, 2), RB!(1));
499 assert_eq!(RB!(-1, 2) + R8!(1, 2), RB!(0));
500 assert_eq!(RB!(-1, 2) + R8!(1), RB!(1, 2));
501 assert_eq!(RB!(7, 2) + R8!(5, 2), RB!(6));
502 assert_eq!(RB!(-7, 2) + R8!(5, 2), RB!(-1));
503 assert_eq!(RB!(-7, 2) - R8!(5, 2), RB!(-6));
504 assert_eq!(
505 RationalBig {
506 sign: Sign::Positive,
507 numerator: unsafe { Ubig::from_inner_unchecked(smallvec![1, 1]) },
508 denominator: unsafe { NonZeroUbig::from_inner_unchecked(smallvec![2]) },
509 } + R8!(1, 2),
510 RationalBig {
511 sign: Sign::Positive,
512 numerator: unsafe { Ubig::from_inner_unchecked(smallvec![(1 << 63) + 1]) },
513 denominator: NonZeroUbig::one(),
514 },
515 );
516
517 assert_eq!(RB!(2, 3) + R8!(8, 1), RB!(8 * 3 + 2, 3));
518 assert_eq!(RB!(8) + R8!(16, 3), RB!(8 * 3 + 16, 3));
519 assert_eq!(RB!(3, 5) + R16!(2, 5), RB!(1));
520
521 assert_eq!(RB!(5) - R32!(7), RB!(-2));
522 assert_eq!(
523 RationalBig {
524 sign: Sign::Positive,
525 numerator: unsafe { Ubig::from_inner_unchecked(smallvec![1, 1]) },
526 denominator: unsafe { NonZeroUbig::from_inner_unchecked(smallvec![2]) },
527 } - R8!(1, 2),
528 RationalBig {
529 sign: Sign::Positive,
530 numerator: unsafe { Ubig::from_inner_unchecked(smallvec![1 << 63]) },
531 denominator: NonZeroUbig::one(),
532 },
533 );
534 assert_eq!(RB!(5, 2) - R8!(2), RB!(1, 2));
535 assert_eq!(RB!(3) - R8!(1, 2), RB!(5, 2));
536 assert_eq!(RB!(16, 3) - R8!(11, 4), RB!(16 * 4 - 11 * 3, 12));
537
538 assert_eq!(RB!(0) + R8!(1, 2), RB!(1, 2));
539 assert_eq!(RB!(0) - R8!(3, 4), RB!(-3, 4));
540 assert_eq!(RB!(-10, 4) + R8!(-10, 8), RB!(-15, 4));
541 assert_eq!(RB!(-10, 4) + R64!(1, 4), RB!(-9, 4));
542 assert_eq!(RB!(-10, 8) + R64!(-10, 9), RB!(-5 * 17, 3 * 3 * 2 * 2));
543 assert_eq!(RB!(-5, 4) + R64!(-5, 4), RB!(-5, 2));
544 assert_eq!(RB!(-7, 6) + R64!(-7, 6), RB!(-7, 3));
545
546 let limit = 10;
547 for a in -limit..limit {
548 for b in 1..limit {
549 for c in -limit..limit {
550 for d in 1..limit {
551 assert_eq!(RB!(a, b as u64) + R64!(c, d as u64), RB!(a * d + c * b, b as u64 * d as u64), "{} / {} - {} / {}", a, b, c, d);
552 }
553 }
554 }
555 }
556 }
557
558 #[test]
559 fn test_mul_div() {
560 assert_eq!(RB!(0) * R8!(18), RB!(0));
561 assert_eq!(RB!(1) * R8!(6), RB!(6));
562 assert_eq!(RB!(-1) * R64!(65488846), -RB!(65488846));
563 assert_eq!(RB!(7, 11) * R8!(11, 7), RB!(1));
564 assert_eq!(RB!(7, 11) * R16!(22, 7), RB!(2));
565 assert_eq!(RB!(14, 33) * R32!(3, 2), RB!(7, 11));
566 assert_eq!(RB!(4, 3) * R64!(0), RB!(0));
567
568 let limit = 10;
569 for a in -limit..limit {
570 for b in 1..limit {
571 for c in -limit..limit {
572 for d in 1..limit {
573 assert_eq!(RB!(a, b as u64) * R64!(c, d as u64), RB!(a * c, (b * d) as u64), "{} / {} * {} / {}", a, b, c, d);
574 }
575 }
576 }
577 }
578 }
579
580 #[test]
584 fn eq_small_respects_sign() {
585 assert_eq!(RB!(2) == R64!(2), true);
586 assert_eq!(RB!(-2) == R64!(2), false);
587 assert_eq!(RB!(2) == R64!(-2), false);
588 assert_eq!(RB!(-2) == R64!(-2), true);
589 assert_eq!(RB!(1, 2) == R8!(1, 2), true);
590 assert_eq!(RB!(-1, 2) == R8!(1, 2), false);
591 assert_eq!(RB!(1, 2) == R8!(-1, 2), false);
592 assert_eq!(RB!(-1, 2) == R8!(-1, 2), true);
593 assert_eq!(RB!(0) == R32!(0), true);
594
595 for numerator in -4_i64..=4 {
597 for denominator in 1_u64..=4 {
598 let small = Rational64::new(numerator, denominator).unwrap();
599 let big = RationalBig::from(small);
600 for other in -4_i64..=4 {
601 let other = Rational64::new(other, denominator).unwrap();
602 #[allow(clippy::cmp_owned, reason = "comparing after conversion is what is being tested")]
603 let converted = big == RationalBig::from(other);
604 assert_eq!(
605 big == other,
606 converted,
607 "{numerator}/{denominator} vs {other}",
608 );
609 }
610 }
611 }
612 }
613
614 #[test]
616 #[should_panic(expected = "attempt to divide by zero")]
617 fn div_zero_by_zero_panics() {
618 let _ = RB!(0) / R8!(0);
619 }
620}