1use super::Q;
14use crate::{
15 error::{MathError, StringConversionError},
16 integer::Z,
17 macros::from::{from_trait, from_type},
18 traits::{AsInteger, Pow},
19};
20use flint_sys::{
21 fmpq::{fmpq, fmpq_canonicalise, fmpq_clear, fmpq_get_d, fmpq_set_str},
22 fmpz::{fmpz_init_set, fmpz_is_zero},
23};
24use std::{ffi::CString, str::FromStr};
25
26impl Q {
27 pub fn from_f64(value: f64) -> Self {
45 let bits: u64 = value.to_bits();
46 let sign = if bits >> 63 == 0 {
47 Q::ONE
48 } else {
49 Q::MINUS_ONE
50 };
51 let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
52 let mantissa = if exponent == 0 {
53 (bits & 0xfffffffffffff) << 1
54 } else {
55 (bits & 0xfffffffffffff) | 0x10000000000000
57 };
58
59 exponent -= 1023 + 52;
62 let shift = match exponent {
63 e if e >= 1 => Q::from(2).pow(e).unwrap(),
65 e => Q::from((1, 2)).pow(e.abs()).unwrap(),
66 };
67
68 sign * Z::from(mantissa) * shift
69 }
70
71 from_type!(f32, f64, Q, Q::from_f64);
72}
73
74impl<IntegerNumerator: AsInteger, IntegerDenominator: AsInteger>
75 From<(IntegerNumerator, IntegerDenominator)> for Q
76{
77 fn from((num, den): (IntegerNumerator, IntegerDenominator)) -> Self {
99 unsafe {
100 let num = num.into_fmpz();
101 let den = den.into_fmpz();
102
103 assert_ne!(den.0, 0, "The denominator can not be zero");
104
105 let mut value = fmpq { num, den };
106 fmpq_canonicalise(&mut value);
107
108 Q { value }
109 }
110 }
111}
112
113impl<Integer: Into<Z>> From<Integer> for Q {
114 fn from(value: Integer) -> Self {
130 let value = value.into();
131 let mut out = Q::default();
133 unsafe { fmpz_init_set(&mut out.value.num, &value.value) }
134 out
135 }
136}
137
138impl From<f64> for Q {
139 fn from(value: f64) -> Self {
157 Q::from_f64(value)
158 }
159}
160
161from_trait!(f32, Q, Q::from_f32);
162
163impl From<&Q> for f64 {
164 fn from(value: &Q) -> Self {
186 unsafe { fmpq_get_d(&value.value) }
187 }
188}
189
190impl From<&Q> for Q {
191 fn from(value: &Q) -> Self {
194 value.clone()
195 }
196}
197
198impl FromStr for Q {
199 type Err = MathError;
200
201 fn from_str(s: &str) -> Result<Self, MathError> {
250 if s.contains(char::is_whitespace) {
251 return Err(StringConversionError::InvalidStringToQInput(s.to_owned()))?;
252 }
253
254 let mut value = fmpq::default();
256
257 let c_string = CString::new(s)?;
258
259 if -1 == unsafe { fmpq_set_str(&mut value, c_string.as_ptr(), 10) } {
268 return Err(StringConversionError::InvalidStringToQInput(s.to_owned()))?;
269 };
270
271 unsafe { fmpq_canonicalise(&mut value) };
273
274 match unsafe { fmpz_is_zero(&value.den) } {
278 0 => Ok(Q { value }),
279 _ => {
280 unsafe {
281 fmpq_clear(&mut value);
282 }
283 Err(MathError::DivisionByZeroError(s.to_owned()))
284 }
285 }
286 }
287}
288
289#[cfg(test)]
290mod tests_from_str {
291 use crate::rational::Q;
292 use std::str::FromStr;
293
294 #[test]
296 fn max_int_positive() {
297 let mut s_1 = (i64::MAX).to_string();
298 s_1.push('/');
299 s_1.push_str(&(i64::MAX).to_string());
300
301 let mut s_2 = ("1/").to_string();
302 s_2.push_str(&(i64::MAX).to_string());
303
304 assert!(Q::from_str(&(i64::MAX).to_string()).is_ok());
305 assert!(Q::from_str(&s_1).is_ok());
306 assert!(Q::from_str(&s_2).is_ok());
307 }
308
309 #[test]
312 fn large_positive() {
313 let mut s_1 = "1".repeat(65);
314 s_1.push('/');
315 s_1.push_str(&"1".repeat(65));
316
317 let mut s_2 = ("1/").to_string();
318 s_2.push_str(&"1".repeat(65));
319
320 assert!(Q::from_str(&"1".repeat(65)).is_ok());
321 assert!(Q::from_str(&s_1).is_ok());
322 assert!(Q::from_str(&s_2).is_ok());
323 }
324
325 #[test]
328 fn max_int_negative() {
329 let mut s_1 = (i64::MIN).to_string();
330 s_1.push('/');
331 s_1.push_str(&(i64::MIN).to_string());
332
333 let mut s_2 = ("1/").to_string();
334 s_2.push_str(&(i64::MIN).to_string());
335
336 assert!(Q::from_str(&(i64::MIN).to_string()).is_ok());
337 assert!(Q::from_str(&s_1).is_ok());
338 assert!(Q::from_str(&s_2).is_ok());
339 }
340
341 #[test]
344 fn large_negative() {
345 let mut s_1 = "-".to_string();
346 s_1.push_str(&"1".repeat(65));
347 s_1.push('/');
348 s_1.push_str(&"1".repeat(65));
349
350 let mut s_2 = ("-1/").to_string();
351 s_2.push_str(&"1".repeat(65));
352
353 assert!(Q::from_str(&"1".repeat(65)).is_ok());
354 assert!(Q::from_str(&s_1).is_ok());
355 assert!(Q::from_str(&s_2).is_ok());
356 }
357
358 #[test]
360 fn no_error_both_minus() {
361 assert!(Q::from_str("-3/-2").is_ok());
362 }
363
364 #[test]
366 fn error_wrong_letters() {
367 assert!(Q::from_str("hbrkt35itu3gg").is_err());
368 }
369
370 #[test]
372 fn error_wrong_order() {
373 assert!(Q::from_str("3/2-").is_err());
374 }
375
376 #[test]
378 fn error_two_divisions() {
379 assert!(Q::from_str("3/2/4").is_err());
380 }
381
382 #[test]
384 fn error_wrong_minus() {
385 assert!(Q::from_str("-3-4/2").is_err());
386 }
387
388 #[test]
390 fn error_whitespace_mid() {
391 assert!(Q::from_str("876/ 543").is_err());
392 }
393
394 #[test]
396 fn error_whitespace_start() {
397 assert!(Q::from_str(" 876543").is_err());
398 }
399
400 #[test]
402 fn error_whitespace_end() {
403 assert!(Q::from_str("876543 ").is_err());
404 }
405
406 #[test]
408 fn error_whitespace_minus() {
409 assert!(Q::from_str("- 876543").is_err());
410 }
411
412 #[test]
414 fn canonical_result() {
415 let one_1 = Q::from_str("1/1").unwrap();
416 let one_2 = Q::from_str("2/2").unwrap();
417 let one_3 = Q::from_str("-42/-42").unwrap();
418
419 let zero_1 = Q::from_str("0/1").unwrap();
420 let zero_2 = Q::from_str("0/42").unwrap();
421
422 assert_eq!(one_1, one_2);
423 assert_eq!(one_1, one_3);
424 assert_eq!(zero_1, zero_2);
425 }
426}
427
428#[cfg(test)]
429mod test_from_int_int {
430 use crate::integer::Z;
431 use crate::integer_mod_q::Zq;
432 use crate::rational::Q;
433
434 #[test]
437 fn different_types() {
438 let int_8: i8 = 10;
439 let int_16: i16 = 10;
440 let int_32: i32 = 10;
441 let int_64: i64 = 10;
442 let uint_8: u8 = 10;
443 let uint_16: u16 = 10;
444 let uint_32: u32 = 10;
445 let uint_64: u64 = 10;
446 let z = Z::from(10);
447 let zq = Zq::from((10, 20));
448
449 let _ = Q::from((int_8, int_8));
451 let _ = Q::from((int_16, int_16));
452 let _ = Q::from((int_32, int_32));
453 let _ = Q::from((int_64, int_64));
454 let _ = Q::from((uint_8, uint_8));
455 let _ = Q::from((uint_16, uint_16));
456 let _ = Q::from((uint_32, uint_32));
457 let _ = Q::from((uint_64, uint_64));
458 let _ = Q::from((z.clone(), z.clone()));
459 let _ = Q::from((zq.clone(), zq.clone()));
460
461 let _ = Q::from((&int_8, &int_8));
463 let _ = Q::from((&int_16, &int_16));
464 let _ = Q::from((&int_32, &int_32));
465 let _ = Q::from((&int_64, &int_64));
466 let _ = Q::from((&uint_8, &uint_8));
467 let _ = Q::from((&uint_16, &uint_16));
468 let _ = Q::from((&uint_32, &uint_32));
469 let _ = Q::from((&uint_64, &uint_64));
470 let _ = Q::from((&z, &z));
471 let _ = Q::from((&zq, &zq));
472
473 let _ = Q::from((int_8, z.clone()));
478 let _ = Q::from((zq.clone(), z.clone()));
479 let _ = Q::from((z.clone(), int_8));
480 let _ = Q::from((z.clone(), zq.clone()));
481 let _ = Q::from((int_8, zq.clone()));
482 let _ = Q::from((zq.clone(), int_8));
483
484 let _ = Q::from((int_8, &z));
486 let _ = Q::from((zq.clone(), &z));
487 let _ = Q::from((z.clone(), &int_8));
488 let _ = Q::from((z.clone(), &zq));
489 let _ = Q::from((int_8, &zq));
490 let _ = Q::from((zq.clone(), &int_8));
491
492 let _ = Q::from((&int_8, z.clone()));
494 let _ = Q::from((&zq, z.clone()));
495 let _ = Q::from((&z, int_8));
496 let _ = Q::from((&z, zq.clone()));
497 let _ = Q::from((&int_8, zq.clone()));
498 let _ = Q::from((&zq, int_8));
499
500 let _ = Q::from((&int_8, &z));
502 let _ = Q::from((&zq, &z));
503 let _ = Q::from((&z, &int_8));
504 let _ = Q::from((&z, &zq));
505 let _ = Q::from((&int_8, &zq));
506 let _ = Q::from((&zq, &int_8));
507 }
508
509 #[test]
511 fn working_large() {
512 let numerator = u64::MAX;
513 let denominator = u64::MAX - 1;
514 let numerator_z = Z::from(numerator);
515 let denominator_z = Z::from(denominator);
516
517 let q_1 = Q::from((numerator, denominator));
518 let q_2 = Q::from((numerator_z, denominator_z));
519
520 assert_eq!(q_1, q_2);
521 }
522
523 #[test]
525 #[should_panic]
526 fn divide_by_zero() {
527 let _ = Q::from((10, 0));
528 }
529
530 #[test]
532 fn negative_small() {
533 let numerator = 10;
534 let denominator = -1;
535
536 let q_1 = Q::from((numerator, denominator));
537 let q_2 = Q::from((-numerator, -denominator));
538
539 assert_eq!(q_1, q_2);
540 }
541
542 #[test]
544 fn canonical_small() {
545 let numerator = 10;
546 let denominator = 1;
547
548 let q_1 = Q::from((numerator, denominator));
549 let q_2 = Q::from((-numerator, -denominator));
550 let q_3 = Q::from((numerator * 2, denominator * 2));
551
552 let q_4_negative = Q::from((-numerator, denominator));
553 let q_5_negative = Q::from((numerator, -denominator));
554
555 assert_eq!(q_1, q_2);
556 assert_eq!(q_1, q_3);
557
558 assert_eq!(q_4_negative, q_5_negative);
559 }
560
561 #[test]
563 fn canonical_large() {
564 let numerator = i64::MAX;
565 let denominator = i64::MAX - 1;
566
567 let numerator_z = Z::from(numerator);
568 let denominator_z = Z::from(denominator);
569
570 let q_1 = Q::from((numerator, denominator));
571 let q_2 = Q::from((-numerator, -denominator));
572 let q_3 = Q::from((&numerator_z, &denominator_z));
573 let q_4 = Q::from((&numerator_z * 2, &denominator_z * 2));
574 let q_5_negative = Q::from((-1 * &numerator_z, &denominator_z));
575 let q_6_negative = Q::from((&numerator_z, -1 * &denominator_z));
576
577 assert_eq!(q_1, q_2);
578 assert_eq!(q_1, q_3);
579 assert_eq!(q_1, q_4);
580 assert_eq!(q_5_negative, q_6_negative);
581 }
582}
583
584#[cfg(test)]
585mod test_try_from_int_int {
586 use crate::integer::Z;
587 use crate::rational::Q;
588
589 #[test]
591 fn test_types_borrowed_small() {
592 let numerator = 10;
593 let denominator = 15;
594
595 let q_1 = Q::from((&(numerator as u8), &(denominator as i8)));
596 let q_2 = Q::from((&(numerator as u16), &(denominator as i16)));
597 let q_3 = Q::from((&(numerator as u32), &(denominator)));
598 let q_4 = Q::from((&(numerator as u64), &(denominator as i64)));
599 let q_5 = Q::from((&Z::from(numerator), &Z::from(denominator)));
600
601 let q_6 = Q::from((&(numerator as i16), &(denominator as u16)));
602 let q_7 = Q::from((&(numerator as i16), &(denominator as i16)));
603
604 assert_eq!(q_1, q_2);
605 assert_eq!(q_1, q_3);
606 assert_eq!(q_1, q_4);
607 assert_eq!(q_1, q_5);
608 assert_eq!(q_1, q_6);
609 assert_eq!(q_1, q_7);
610 }
611
612 #[test]
614 fn working_large() {
615 let numerator = u64::MAX;
616 let denominator = u64::MAX - 1;
617 let numerator_z = Z::from(numerator);
618 let denominator_z = Z::from(denominator);
619
620 let q_1 = Q::from((&numerator, &denominator));
621 let q_2 = Q::from((&numerator_z, &denominator_z));
622
623 assert_eq!(q_1, q_2);
624 }
625
626 #[test]
628 #[should_panic]
629 fn divide_by_zero() {
630 let numerator = 10;
631 let denominator = 0;
632
633 let _ = Q::from((&numerator, &denominator));
634 }
635
636 #[test]
638 fn negative_small() {
639 let numerator = 10;
640 let denominator = -1;
641
642 let q_1 = Q::from((&numerator, &denominator));
643 let q_2 = Q::from((&-numerator, &-denominator));
644
645 assert_eq!(q_1, q_2);
646 }
647
648 #[test]
650 fn canonical_small() {
651 let numerator = 10;
652 let denominator = 1;
653
654 let q_1 = Q::from((&numerator, &denominator));
655 let q_2 = Q::from((&-numerator, &-denominator));
656 let q_3 = Q::from((&(numerator * 2), &(denominator * 2)));
657
658 let q_4_negative = Q::from((&-numerator, &denominator));
659 let q_5_negative = Q::from((&numerator, &-denominator));
660
661 assert_eq!(q_1, q_2);
662 assert_eq!(q_1, q_3);
663
664 assert_eq!(q_4_negative, q_5_negative);
665 }
666
667 #[test]
669 fn canonical_large() {
670 let numerator = i64::MAX;
671 let denominator = i64::MAX - 1;
672
673 let numerator_z = Z::from(numerator);
674 let denominator_z = Z::from(denominator);
675
676 let q_1 = Q::from((&numerator, &denominator));
677 let q_2 = Q::from((&-numerator, &-denominator));
678 let q_3 = Q::from((&numerator_z, &denominator_z));
679 let q_4 = Q::from((&(&numerator_z * Z::from(2)), &(&denominator_z * Z::from(2))));
680 let q_5_negative = Q::from((&(&numerator_z * Z::from(-1)), &denominator_z));
681 let q_6_negative = Q::from((&numerator_z, &(&denominator_z * Z::from(-1))));
682
683 assert_eq!(q_1, q_2);
684 assert_eq!(q_1, q_3);
685 assert_eq!(q_1, q_4);
686 assert_eq!(q_5_negative, q_6_negative);
687 }
688}
689
690#[cfg(test)]
691mod test_from_z {
692 use super::Q;
693 use crate::integer::Z;
694
695 #[test]
698 fn from_trait() {
699 let z_1 = Z::from(u64::MAX);
700 let z_2 = Z::from(17);
701
702 assert_eq!(Q::from(u64::MAX), Q::from(z_1));
703 assert_eq!(Q::from(17), Q::from(z_2));
704 }
705
706 #[test]
709 fn from_into_z() {
710 let _ = Q::from(u8::MAX);
711 let _ = Q::from(u16::MAX);
712 let _ = Q::from(u32::MAX);
713 let _ = Q::from(u64::MAX);
714
715 let _ = Q::from(i8::MIN);
716 let _ = Q::from(i16::MIN);
717 let _ = Q::from(i32::MIN);
718 let _ = Q::from(i64::MIN);
719 }
720}
721
722#[cfg(test)]
723mod test_from_float {
724 use super::Q;
725 use std::{
726 f64::consts::{E, LN_2, LN_10},
727 str::FromStr,
728 };
729
730 #[test]
732 fn large_value() {
733 let a: f64 = 10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104.0;
735
736 let q = Q::from(a);
737
738 let cmp = Q::from_str("10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104")
739 .unwrap();
740 assert_eq!(q, cmp);
741 }
742
743 #[test]
745 #[allow(clippy::excessive_precision)]
746 fn small_value() {
747 let a: f64 = 0.1000000000000000055511151231257827021181583404541015625;
749
750 let q = Q::from(a);
751
752 let cmp = Q::from_str("1000000000000000055511151231257827021181583404541015625/10000000000000000000000000000000000000000000000000000000")
753 .unwrap();
754 assert_eq!(q, cmp);
755 }
756
757 #[test]
759 fn positive() {
760 let numerator = 150001;
761 let denominator = 16;
762
763 let value = Q::from(numerator as f64 / denominator as f64);
764
765 let cmp = Q::from((numerator, denominator));
766 assert_eq!(cmp, value);
767 }
768
769 #[test]
771 fn negative() {
772 let numerator = 150001;
773 let denominator = -8;
774
775 let value = Q::from(numerator as f64 / denominator as f64);
776
777 let cmp = Q::from((numerator, denominator));
778 assert_eq!(cmp, value);
779 }
780
781 #[test]
783 fn from_trait() {
784 let _ = Q::from(E);
785 let _ = Q::from(LN_10);
786 let _ = Q::from(LN_2);
787 }
788
789 #[test]
791 fn from_f32_available() {
792 let f: f32 = 42.17;
793
794 let _ = Q::from(f);
795 let _ = Q::from_f32(f);
796 }
797}
798
799#[cfg(test)]
800mod test_into_float {
801 use super::*;
802
803 #[test]
806 fn one_half() {
807 let one_half = Q::from((1, 2));
808 let float = f64::from(&one_half);
809
810 assert_eq!(0.5, float);
811 }
812
813 #[test]
816 fn round_trip() {
817 let start_values = vec![
818 0.0,
819 0.1,
820 f64::MAX,
821 f64::MIN,
822 f64::MIN_POSITIVE,
823 f64::EPSILON,
824 ];
825
826 for start in start_values {
827 let end = f64::from(&Q::from(start));
828
829 assert_eq!(start, end);
830 }
831 }
832}
833
834#[cfg(test)]
835mod test_from_q_ref {
836 use crate::rational::Q;
837
838 #[test]
840 fn availability() {
841 let q = Q::from(u64::MAX);
842
843 let _ = Q::from(&q);
844 }
845}