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