1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
49 core::{errors::capture_backtrace, policies::StrictFinitePolicy},
50 functions::FunctionErrors,
51 kernels::{RawComplexTrait, RawRealTrait, RawScalarTrait},
52};
53use duplicate::duplicate_item;
54use num::Complex;
55use num::Zero;
56use std::backtrace::Backtrace;
57use thiserror::Error;
58use try_create::ValidationPolicy;
59
60#[derive(Debug, Error)]
80pub enum LogarithmRealInputErrors<RawReal: RawRealTrait> {
81 #[error("negative argument ({value})!")]
86 NegativeArgument {
87 value: RawReal,
89
90 backtrace: Backtrace,
92 },
93
94 #[error("zero argument!")]
99 ZeroArgument {
100 backtrace: Backtrace,
102 },
103
104 #[error("the argument is invalid!")]
109 InvalidArgument {
110 #[source]
112 #[backtrace]
113 source: <RawReal as RawScalarTrait>::ValidationErrors,
114 },
115}
116
117#[derive(Debug, Error)]
134pub enum LogarithmComplexInputErrors<RawComplex: RawComplexTrait> {
135 #[error("the argument is zero!")]
140 ZeroArgument {
141 backtrace: Backtrace,
143 },
144
145 #[error("the argument is invalid!")]
150 InvalidArgument {
151 #[source]
153 #[backtrace]
154 source: <RawComplex as RawScalarTrait>::ValidationErrors,
155 },
156}
157
158pub type LogarithmRealErrors<RawReal> = FunctionErrors<
175 LogarithmRealInputErrors<RawReal>,
176 <RawReal as RawScalarTrait>::ValidationErrors,
177>;
178
179pub type LogarithmComplexErrors<RawComplex> = FunctionErrors<
196 LogarithmComplexInputErrors<RawComplex>,
197 <RawComplex as RawScalarTrait>::ValidationErrors,
198>;
199
200#[duplicate_item(
201 trait_name try_func func trait_doc try_func_doc func_doc err_doc;
202 [Ln] [try_ln] [ln] ["Trait for computing the [*natural logarithm*](https://en.wikipedia.org/wiki/Natural_logarithm) (base `e`) of a number.\n\nProvides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_ln` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n- `try_ln`: Computes the *natural logarithm* of `self` and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n- `ln`: Computes the *natural logarithm* of `self` and directly returns the computed value. This method may panic (in Debug mode) if the computation fails."] ["Computes the *natural logarithm* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Ln::Error`] type."] ["Computes the *natural logarithm* of `self` and directly returns the computed value.\n\nThis method may panic (in Debug mode) if the computation fails.\n\n# Panics\n\nThis method may panic (in Debug mode) if the computation fails. It is recommended to use the `try_ln` method for safe computations."] ["The error type that is returned by the `try_ln` method."];
203 [Log10] [try_log10] [log10] ["Trait for computing the [*base-10 logarithm*](https://en.wikipedia.org/wiki/Common_logarithm) of a number.\n\nProvides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_log10` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n- `try_log10`: Computes the *base-10 logarithm* of `self` and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n- `log10`: Computes the *base-10 logarithm* of `self` and directly returns the computed value. This method may panic (in Debug mode) if the computation fails."] ["Computes the *base-10 logarithm* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Log10::Error`] type."] ["Computes the *base-10 logarithm* of `self` and directly returns the computed value.\n\nThis method may panic (in Debug mode) if the computation fails.\n\n# Panics\n\nThis method may panic (in Debug mode) if the computation fails. It is recommended to use the `try_log10` method for safe computations."] ["The error type that is returned by the `try_log10` method."];
204 [Log2] [try_log2] [log2] ["Trait for computing the [*base-2 logarithm*](https://en.wikipedia.org/wiki/Binary_logarithm) of a number.\n\nProvides both a fallible method that returns a [`Result`] and a panicking method that directly returns the computed value or panics on invalid input.\n\n# Associated Types\n\n- `Error`: The error type that is returned by the `try_log2` method. This type must implement the [`std::error::Error`] trait.\n\n# Required Methods\n\n- `try_log2`: Computes the *base-2 logarithm* of `self` and returns a [`Result`]. If the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n- `log2`: Computes the *base-2 logarithm* of `self` and directly returns the computed value. This method may panic (in Debug mode) if the computation fails."] ["Computes the *base-2 logarithm* of `self` and returns a [`Result`].\n\nIf the computation is successful, it returns [`Ok`] with the computed value. If an error occurs, it returns [`Err`] with the associated error.\n\n# Errors\n\nThis method returns an error if the computation fails. The error type is defined by the associated [`Log2::Error`] type."] ["Computes the *base-2 logarithm* of `self` and directly returns the computed value.\n\nThis method may panic (in Debug mode) if the computation fails.\n\n# Panics\n\nThis method may panic (in Debug mode) if the computation fails. It is recommended to use the `try_log2` method for safe computations."] ["The error type that is returned by the `try_log2` method."];
205)]
206#[doc = trait_doc]
207pub trait trait_name: Sized {
208 #[doc = err_doc]
209 type Error: std::error::Error;
210
211 #[doc = try_func_doc]
212 #[must_use = "this `Result` may contain an error that should be handled"]
213 fn try_func(self) -> Result<Self, Self::Error>;
214
215 #[doc = func_doc]
216 fn func(self) -> Self;
217}
218
219#[duplicate_item(
220 trait_name try_func func;
221 [Ln] [try_ln] [ln];
222 [Log10] [try_log10] [log10];
223 [Log2] [try_log2] [log2];
224)]
225impl trait_name for f64 {
226 type Error = LogarithmRealErrors<Self>;
227
228 #[inline(always)]
229 fn try_func(self) -> Result<Self, Self::Error> {
230 StrictFinitePolicy::<Self, 53>::validate(self)
231 .map_err(|e| LogarithmRealInputErrors::InvalidArgument { source: e }.into())
232 .and_then(|v| {
233 if v < 0.0 {
234 Err(LogarithmRealInputErrors::NegativeArgument {
235 value: v,
236 backtrace: capture_backtrace(),
237 }
238 .into())
239 } else if v == 0. {
240 Err(LogarithmRealInputErrors::ZeroArgument {
241 backtrace: capture_backtrace(),
242 }
243 .into())
244 } else {
245 StrictFinitePolicy::<Self, 53>::validate(f64::func(v))
246 .map_err(|e| LogarithmRealErrors::Output { source: e })
247 }
248 })
249 }
250
251 #[inline(always)]
252 fn func(self) -> Self {
253 #[cfg(debug_assertions)]
254 {
255 self.try_func().unwrap()
256 }
257 #[cfg(not(debug_assertions))]
258 {
259 f64::func(self)
260 }
261 }
262}
263
264#[duplicate_item(
265 trait_name try_func func;
266 [Ln] [try_ln] [ln];
267 [Log10] [try_log10] [log10];
268 [Log2] [try_log2] [log2];
269)]
270impl trait_name for Complex<f64> {
271 type Error = LogarithmComplexErrors<Self>;
272
273 #[inline(always)]
274 fn try_func(self) -> Result<Self, Self::Error> {
275 StrictFinitePolicy::<Self, 53>::validate(self)
276 .map_err(|e| LogarithmComplexInputErrors::InvalidArgument { source: e }.into())
277 .and_then(|v| {
278 if Zero::is_zero(&v) {
279 Err(LogarithmComplexInputErrors::ZeroArgument {
280 backtrace: capture_backtrace(),
281 }
282 .into())
283 } else {
284 StrictFinitePolicy::<Self, 53>::validate(Complex::func(v))
285 .map_err(|e| LogarithmComplexErrors::Output { source: e })
286 }
287 })
288 }
289
290 #[inline(always)]
291 fn func(self) -> Self {
292 #[cfg(debug_assertions)]
293 {
294 self.try_func().unwrap()
295 }
296 #[cfg(not(debug_assertions))]
297 {
298 Complex::func(self)
299 }
300 }
301}
302pub trait LogarithmFunctions: Ln + Log2 + Log10 {}
348
349#[duplicate_item(
350 T;
351 [f64];
352 [Complex<f64>];
353)]
354impl LogarithmFunctions for T {}
355#[cfg(test)]
359mod tests {
360 use super::*;
361
362 #[cfg(feature = "rug")]
363 use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
364
365 #[cfg(feature = "rug")]
366 use try_create::TryNew;
367
368 mod ln {
369 use super::*;
370
371 mod native64 {
372 use super::*;
373
374 mod real {
375 use super::*;
376
377 #[test]
378 fn test_f64_ln_valid() {
379 let value = 10.0;
380 let expected_result = std::f64::consts::LN_10;
381 assert_eq!(value.ln(), expected_result);
382 assert_eq!(value.try_ln().unwrap(), expected_result);
383 }
384
385 #[test]
386 fn test_f64_ln_zero() {
387 let value = 0.0;
388 let result = value.try_ln();
389 assert!(matches!(
390 result,
391 Err(LogarithmRealErrors::Input {
392 source: LogarithmRealInputErrors::ZeroArgument { .. }
393 })
394 ));
395 }
396
397 #[test]
398 fn test_f64_ln_negative() {
399 let value = -10.0;
400 let result = value.try_ln();
401 assert!(matches!(
402 result,
403 Err(LogarithmRealErrors::Input {
404 source: LogarithmRealInputErrors::NegativeArgument { .. }
405 })
406 ));
407 }
408
409 #[test]
410 fn test_f64_ln_one() {
411 let value = 1.0;
412 let expected_result = 0.0;
413 assert_eq!(value.ln(), expected_result);
414 assert_eq!(value.try_ln().unwrap(), expected_result);
415 }
416
417 #[test]
418 fn test_f64_ln_infinity() {
419 let value = f64::INFINITY;
420 let result = value.try_ln();
421 assert!(matches!(
422 result,
423 Err(LogarithmRealErrors::Input {
424 source: LogarithmRealInputErrors::InvalidArgument { .. }
425 })
426 ));
427 }
428
429 #[test]
430 fn test_f64_ln_nan() {
431 let value = f64::NAN;
432 let result = value.try_ln();
433 assert!(matches!(
434 result,
435 Err(LogarithmRealErrors::Input {
436 source: LogarithmRealInputErrors::InvalidArgument { .. }
437 })
438 ));
439 }
440 }
441
442 mod complex {
443 use super::*;
444
445 #[test]
446 fn test_complex_f64_ln_valid() {
447 let value = Complex::new(10.0, 0.0);
448 let expected_result = Complex::new(std::f64::consts::LN_10, 0.0);
449 assert_eq!(value.ln(), expected_result);
450 assert_eq!(value.try_ln().unwrap(), expected_result);
451 }
452
453 #[test]
454 fn test_complex_f64_ln_zero() {
455 let value = Complex::new(0.0, 0.0);
456 let result = value.try_ln();
457 assert!(matches!(
458 result,
459 Err(LogarithmComplexErrors::Input {
460 source: LogarithmComplexInputErrors::ZeroArgument { .. }
461 })
462 ));
463 }
464
465 #[test]
466 fn test_complex_f64_ln_negative() {
467 let value = Complex::new(-10.0, 0.0);
468 let expected_result =
469 Complex::new(std::f64::consts::LN_10, std::f64::consts::PI);
470 assert_eq!(value.ln(), expected_result);
471 assert_eq!(value.try_ln().unwrap(), expected_result);
472 }
473
474 #[test]
475 fn test_complex_f64_ln_one() {
476 let value = Complex::new(1.0, 0.0);
477 let expected_result = Complex::new(0.0, 0.0);
478 assert_eq!(value.ln(), expected_result);
479 assert_eq!(value.try_ln().unwrap(), expected_result);
480 }
481
482 #[test]
483 fn test_complex_f64_ln_infinity() {
484 let value = Complex::new(f64::INFINITY, 0.0);
485 let result = value.try_ln();
486 assert!(matches!(
487 result,
488 Err(LogarithmComplexErrors::Input {
489 source: LogarithmComplexInputErrors::InvalidArgument { .. }
490 })
491 ));
492
493 let value = Complex::new(0.0, f64::INFINITY);
494 let result = value.try_ln();
495 assert!(matches!(
496 result,
497 Err(LogarithmComplexErrors::Input {
498 source: LogarithmComplexInputErrors::InvalidArgument { .. }
499 })
500 ));
501 }
502
503 #[test]
504 fn test_complex_f64_ln_nan() {
505 let value = Complex::new(f64::NAN, 0.0);
506 let result = value.try_ln();
507 assert!(matches!(
508 result,
509 Err(LogarithmComplexErrors::Input {
510 source: LogarithmComplexInputErrors::InvalidArgument { .. }
511 })
512 ));
513
514 let value = Complex::new(0.0, f64::NAN);
515 let result = value.try_ln();
516 assert!(matches!(
517 result,
518 Err(LogarithmComplexErrors::Input {
519 source: LogarithmComplexInputErrors::InvalidArgument { .. }
520 })
521 ));
522 }
523 }
524 }
525
526 #[cfg(feature = "rug")]
527 mod rug53 {
528 use super::*;
529 use rug::{Complex, Float};
530
531 mod real {
532 use super::*;
533
534 #[test]
535 fn test_real_ln_valid() {
536 let value =
537 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 10.0)).unwrap();
538 let expected_result = RealRugStrictFinite::<53>::try_new(Float::with_val(
539 53,
540 std::f64::consts::LN_10,
541 ))
542 .unwrap();
543 assert_eq!(value.clone().ln(), expected_result);
544 assert_eq!(value.try_ln().unwrap(), expected_result);
545 }
546
547 #[test]
548 fn test_real_ln_zero() {
549 let value =
550 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
551 let result = value.try_ln();
552 assert!(matches!(
553 result,
554 Err(LogarithmRealErrors::Input {
555 source: LogarithmRealInputErrors::ZeroArgument { .. }
556 })
557 ));
558 }
559
560 #[test]
561 fn test_real_ln_negative() {
562 let value =
563 RealRugStrictFinite::<53>::try_new(Float::with_val(53, -10.0)).unwrap();
564 let result = value.try_ln();
565 assert!(matches!(
566 result,
567 Err(LogarithmRealErrors::Input {
568 source: LogarithmRealInputErrors::NegativeArgument { .. }
569 })
570 ));
571 }
572
573 #[test]
574 fn test_real_ln_one() {
575 let value =
576 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
577 let expected_result =
578 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
579 assert_eq!(value.clone().ln(), expected_result);
580 assert_eq!(value.try_ln().unwrap(), expected_result);
581 }
582 }
583
584 mod complex {
585 use super::*;
586
587 #[test]
588 fn test_complex_ln_valid() {
589 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
590 53,
591 (Float::with_val(53, 10.0), Float::with_val(53, 0.0)),
592 ))
593 .unwrap();
594 let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
595 53,
596 (
597 Float::with_val(53, std::f64::consts::LN_10),
598 Float::with_val(53, 0.0),
599 ),
600 ))
601 .unwrap();
602 assert_eq!(value.clone().ln(), expected_result);
603 assert_eq!(value.try_ln().unwrap(), expected_result);
604 }
605
606 #[test]
607 fn test_complex_ln_zero() {
608 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
609 53,
610 (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
611 ))
612 .unwrap();
613 let result = value.try_ln();
614 assert!(matches!(
615 result,
616 Err(LogarithmComplexErrors::Input {
617 source: LogarithmComplexInputErrors::ZeroArgument { .. }
618 })
619 ));
620 }
621
622 #[test]
623 fn test_complex_ln_negative() {
624 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
625 53,
626 (Float::with_val(53, -10.0), Float::with_val(53, 0.0)),
627 ))
628 .unwrap();
629 let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
630 53,
631 (
632 Float::with_val(53, std::f64::consts::LN_10),
633 Float::with_val(53, std::f64::consts::PI),
634 ),
635 ))
636 .unwrap();
637 assert_eq!(value.clone().ln(), expected_result);
638 assert_eq!(value.try_ln().unwrap(), expected_result);
639 }
640
641 #[test]
642 fn test_complex_ln_one() {
643 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
644 53,
645 (Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
646 ))
647 .unwrap();
648 let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
649 53,
650 (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
651 ))
652 .unwrap();
653 assert_eq!(value.clone().ln(), expected_result);
654 assert_eq!(value.try_ln().unwrap(), expected_result);
655 }
656 }
657 }
658 }
659
660 mod log10 {
661 use super::*;
662
663 mod native64 {
664 use super::*;
665
666 mod real {
667 use super::*;
668
669 #[test]
670 fn test_f64_log10_valid() {
671 let value = 10.0;
672 let expected_result = 1.0;
673 assert_eq!(value.log10(), expected_result);
674 assert_eq!(value.try_log10().unwrap(), expected_result);
675 }
676
677 #[test]
678 fn test_f64_log10_zero() {
679 let value = 0.0;
680 let result = value.try_log10();
681 assert!(matches!(
682 result,
683 Err(LogarithmRealErrors::Input {
684 source: LogarithmRealInputErrors::ZeroArgument { .. }
685 })
686 ));
687 }
688
689 #[test]
690 fn test_f64_log10_negative() {
691 let value = -10.0;
692 let result = value.try_log10();
693 assert!(matches!(
694 result,
695 Err(LogarithmRealErrors::Input {
696 source: LogarithmRealInputErrors::NegativeArgument { .. }
697 })
698 ));
699 }
700
701 #[test]
702 fn test_f64_log10_one() {
703 let value = 1.0;
704 let expected_result = 0.0;
705 assert_eq!(value.log10(), expected_result);
706 assert_eq!(value.try_log10().unwrap(), expected_result);
707 }
708
709 #[test]
710 fn test_f64_log10_infinity() {
711 let value = f64::INFINITY;
712 let result = value.try_log10();
713 assert!(matches!(
714 result,
715 Err(LogarithmRealErrors::Input {
716 source: LogarithmRealInputErrors::InvalidArgument { .. }
717 })
718 ));
719 }
720
721 #[test]
722 fn test_f64_log10_nan() {
723 let value = f64::NAN;
724 let result = value.try_log10();
725 assert!(matches!(
726 result,
727 Err(LogarithmRealErrors::Input {
728 source: LogarithmRealInputErrors::InvalidArgument { .. }
729 })
730 ));
731 }
732 }
733
734 mod complex {
735 use super::*;
736
737 #[test]
738 fn test_complex_f64_log10_valid() {
739 let value = Complex::new(10.0, 0.0);
740 let expected_result = Complex::new(1.0, 0.0);
741 assert_eq!(value.log10(), expected_result);
742 assert_eq!(value.try_log10().unwrap(), expected_result);
743 }
744
745 #[test]
746 fn test_complex_f64_log10_zero() {
747 let value = Complex::new(0.0, 0.0);
748 let result = value.try_log10();
749 assert!(matches!(
750 result,
751 Err(LogarithmComplexErrors::Input {
752 source: LogarithmComplexInputErrors::ZeroArgument { .. }
753 })
754 ));
755 }
756
757 #[test]
758 fn test_complex_f64_log10_negative() {
759 let value = Complex::new(-10.0, 0.0);
760 let expected_result = Complex::new(1.0, 1.3643763538418412);
761 assert_eq!(value.log10(), expected_result);
762 assert_eq!(value.try_log10().unwrap(), expected_result);
763 }
764
765 #[test]
766 fn test_complex_f64_log10_one() {
767 let value = Complex::new(1.0, 0.0);
768 let expected_result = Complex::new(0.0, 0.0);
769 assert_eq!(value.log10(), expected_result);
770 assert_eq!(value.try_log10().unwrap(), expected_result);
771 }
772
773 #[test]
774 fn test_complex_f64_log10_infinity() {
775 let value = Complex::new(f64::INFINITY, 0.0);
776 let result = value.try_log10();
777 assert!(matches!(
778 result,
779 Err(LogarithmComplexErrors::Input {
780 source: LogarithmComplexInputErrors::InvalidArgument { .. }
781 })
782 ));
783
784 let value = Complex::new(0.0, f64::INFINITY);
785 let result = value.try_log10();
786 assert!(matches!(
787 result,
788 Err(LogarithmComplexErrors::Input {
789 source: LogarithmComplexInputErrors::InvalidArgument { .. }
790 })
791 ));
792 }
793
794 #[test]
795 fn test_complex_f64_log10_nan() {
796 let value = Complex::new(f64::NAN, 0.0);
797 let result = value.try_log10();
798 assert!(matches!(
799 result,
800 Err(LogarithmComplexErrors::Input {
801 source: LogarithmComplexInputErrors::InvalidArgument { .. }
802 })
803 ));
804
805 let value = Complex::new(0.0, f64::NAN);
806 let result = value.try_log10();
807 assert!(matches!(
808 result,
809 Err(LogarithmComplexErrors::Input {
810 source: LogarithmComplexInputErrors::InvalidArgument { .. }
811 })
812 ));
813 }
814 }
815 }
816
817 #[cfg(feature = "rug")]
818 mod rug53 {
819 use super::*;
820 use rug::{Complex, Float};
821
822 mod real {
823 use super::*;
824
825 #[test]
826 fn test_real_log10_valid() {
827 let value =
828 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 10.0)).unwrap();
829 let expected_result =
830 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
831 assert_eq!(value.clone().log10(), expected_result);
832 assert_eq!(value.try_log10().unwrap(), expected_result);
833 }
834
835 #[test]
836 fn test_real_log10_zero() {
837 let value =
838 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
839 let result = value.try_log10();
840 assert!(matches!(
841 result,
842 Err(LogarithmRealErrors::Input {
843 source: LogarithmRealInputErrors::ZeroArgument { .. }
844 })
845 ));
846 }
847
848 #[test]
849 fn test_real_log10_negative() {
850 let value =
851 RealRugStrictFinite::<53>::try_new(Float::with_val(53, -10.0)).unwrap();
852 let result = value.try_log10();
853 assert!(matches!(
854 result,
855 Err(LogarithmRealErrors::Input {
856 source: LogarithmRealInputErrors::NegativeArgument { .. }
857 })
858 ));
859 }
860
861 #[test]
862 fn test_real_log10_one() {
863 let value =
864 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
865 let expected_result =
866 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
867 assert_eq!(value.clone().log10(), expected_result);
868 assert_eq!(value.try_log10().unwrap(), expected_result);
869 }
870 }
871
872 mod complex {
873 use super::*;
874
875 #[test]
876 fn test_complex_log10_valid() {
877 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
878 53,
879 (Float::with_val(53, 10.0), Float::with_val(53, 0.0)),
880 ))
881 .unwrap();
882 let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
883 53,
884 (Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
885 ))
886 .unwrap();
887 assert_eq!(value.clone().log10(), expected_result);
888 assert_eq!(value.try_log10().unwrap(), expected_result);
889 }
890
891 #[test]
892 fn test_complex_log10_zero() {
893 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
894 53,
895 (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
896 ))
897 .unwrap();
898 let result = value.try_log10();
899 assert!(matches!(
900 result,
901 Err(LogarithmComplexErrors::Input {
902 source: LogarithmComplexInputErrors::ZeroArgument { .. }
903 })
904 ));
905 }
906
907 #[test]
908 fn test_complex_log10_negative() {
909 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
910 53,
911 (Float::with_val(53, -10.0), Float::with_val(53, 0.0)),
912 ))
913 .unwrap();
914 let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
915 53,
916 (
917 Float::with_val(53, 1.0),
918 Float::with_val(53, 1.3643763538418414),
919 ),
920 ))
921 .unwrap();
922 assert_eq!(value.clone().log10(), expected_result);
923 assert_eq!(value.try_log10().unwrap(), expected_result);
924 }
925
926 #[test]
927 fn test_complex_log10_one() {
928 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
929 53,
930 (Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
931 ))
932 .unwrap();
933 let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
934 53,
935 (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
936 ))
937 .unwrap();
938 assert_eq!(value.clone().log10(), expected_result);
939 assert_eq!(value.try_log10().unwrap(), expected_result);
940 }
941 }
942 }
943 }
944
945 mod log2 {
946 use super::*;
947
948 mod native64 {
949 use super::*;
950
951 mod real {
952 use super::*;
953
954 #[test]
955 fn test_f64_log2_valid() {
956 let value = 10.0;
957 let expected_result = std::f64::consts::LOG2_10;
958 assert_eq!(value.log2(), expected_result);
959 assert_eq!(value.try_log2().unwrap(), expected_result);
960 }
961
962 #[test]
963 fn test_f64_log2_zero() {
964 let value = 0.0;
965 let result = value.try_log2();
966 assert!(matches!(
967 result,
968 Err(LogarithmRealErrors::Input {
969 source: LogarithmRealInputErrors::ZeroArgument { .. }
970 })
971 ));
972 }
973
974 #[test]
975 fn test_f64_log2_negative() {
976 let value = -10.0;
977 let result = value.try_log2();
978 assert!(matches!(
979 result,
980 Err(LogarithmRealErrors::Input {
981 source: LogarithmRealInputErrors::NegativeArgument { .. }
982 })
983 ));
984 }
985
986 #[test]
987 fn test_f64_log2_one() {
988 let value = 1.0;
989 let expected_result = 0.0;
990 assert_eq!(value.log2(), expected_result);
991 assert_eq!(value.try_log2().unwrap(), expected_result);
992 }
993
994 #[test]
995 fn test_f64_log2_infinity() {
996 let value = f64::INFINITY;
997 let result = value.try_log2();
998 assert!(matches!(
999 result,
1000 Err(LogarithmRealErrors::Input {
1001 source: LogarithmRealInputErrors::InvalidArgument { .. }
1002 })
1003 ));
1004 }
1005
1006 #[test]
1007 fn test_f64_log2_nan() {
1008 let value = f64::NAN;
1009 let result = value.try_log2();
1010 assert!(matches!(
1011 result,
1012 Err(LogarithmRealErrors::Input {
1013 source: LogarithmRealInputErrors::InvalidArgument { .. }
1014 })
1015 ));
1016 }
1017 }
1018
1019 mod complex {
1020 use super::*;
1021
1022 #[test]
1023 fn test_complex_f64_log2_valid() {
1024 let value = Complex::new(10.0, 0.0);
1025 let expected_result = Complex::new(3.3219280948873626, 0.0);
1026 assert_eq!(value.log2(), expected_result);
1027 assert_eq!(value.try_log2().unwrap(), expected_result);
1028 }
1029
1030 #[test]
1031 fn test_complex_f64_log2_zero() {
1032 let value = Complex::new(0.0, 0.0);
1033 let result = value.try_log2();
1034 assert!(matches!(
1035 result,
1036 Err(LogarithmComplexErrors::Input {
1037 source: LogarithmComplexInputErrors::ZeroArgument { .. }
1038 })
1039 ));
1040 }
1041
1042 #[test]
1043 fn test_complex_f64_log2_negative() {
1044 let value = Complex::new(-10.0, 0.0);
1045 let expected_result = Complex::new(3.3219280948873626, 4.532360141827194);
1046 assert_eq!(value.log2(), expected_result);
1047 assert_eq!(value.try_log2().unwrap(), expected_result);
1048 }
1049
1050 #[test]
1051 fn test_complex_f64_log2_one() {
1052 let value = Complex::new(1.0, 0.0);
1053 let expected_result = Complex::new(0.0, 0.0);
1054 assert_eq!(value.log2(), expected_result);
1055 assert_eq!(value.try_log2().unwrap(), expected_result);
1056 }
1057
1058 #[test]
1059 fn test_complex_f64_log2_infinity() {
1060 let value = Complex::new(f64::INFINITY, 0.0);
1061 let result = value.try_log2();
1062 assert!(matches!(
1063 result,
1064 Err(LogarithmComplexErrors::Input {
1065 source: LogarithmComplexInputErrors::InvalidArgument { .. }
1066 })
1067 ));
1068
1069 let value = Complex::new(0.0, f64::INFINITY);
1070 let result = value.try_log2();
1071 assert!(matches!(
1072 result,
1073 Err(LogarithmComplexErrors::Input {
1074 source: LogarithmComplexInputErrors::InvalidArgument { .. }
1075 })
1076 ));
1077 }
1078
1079 #[test]
1080 fn test_complex_f64_log2_nan() {
1081 let value = Complex::new(f64::NAN, 0.0);
1082 let result = value.try_log2();
1083 assert!(matches!(
1084 result,
1085 Err(LogarithmComplexErrors::Input {
1086 source: LogarithmComplexInputErrors::InvalidArgument { .. }
1087 })
1088 ));
1089
1090 let value = Complex::new(0.0, f64::NAN);
1091 let result = value.try_log2();
1092 assert!(matches!(
1093 result,
1094 Err(LogarithmComplexErrors::Input {
1095 source: LogarithmComplexInputErrors::InvalidArgument { .. }
1096 })
1097 ));
1098 }
1099 }
1100 }
1101
1102 #[cfg(feature = "rug")]
1103 mod rug53 {
1104 use super::*;
1105 use rug::{Complex, Float};
1106
1107 mod real {
1108 use super::*;
1109
1110 #[test]
1111 fn test_real_log2_valid() {
1112 let value =
1113 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 10.0)).unwrap();
1114 let expected_result = RealRugStrictFinite::<53>::try_new(Float::with_val(
1115 53,
1116 std::f64::consts::LOG2_10,
1117 ))
1118 .unwrap();
1119 assert_eq!(value.clone().log2(), expected_result);
1120 assert_eq!(value.try_log2().unwrap(), expected_result);
1121 }
1122
1123 #[test]
1124 fn test_real_log2_zero() {
1125 let value =
1126 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
1127 let result = value.try_log2();
1128 assert!(matches!(
1129 result,
1130 Err(LogarithmRealErrors::Input {
1131 source: LogarithmRealInputErrors::ZeroArgument { .. }
1132 })
1133 ));
1134 }
1135
1136 #[test]
1137 fn test_real_log2_negative() {
1138 let value =
1139 RealRugStrictFinite::<53>::try_new(Float::with_val(53, -10.0)).unwrap();
1140 let result = value.try_log2();
1141 assert!(matches!(
1142 result,
1143 Err(LogarithmRealErrors::Input {
1144 source: LogarithmRealInputErrors::NegativeArgument { .. }
1145 })
1146 ));
1147 }
1148
1149 #[test]
1150 fn test_real_log2_one() {
1151 let value =
1152 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
1153 let expected_result =
1154 RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
1155 assert_eq!(value.clone().log2(), expected_result);
1156 assert_eq!(value.try_log2().unwrap(), expected_result);
1157 }
1158 }
1159
1160 mod complex {
1161 use super::*;
1162
1163 #[test]
1164 fn test_complex_log2_valid() {
1165 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1166 53,
1167 (Float::with_val(53, 10.0), Float::with_val(53, 0.0)),
1168 ))
1169 .unwrap();
1170 let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1171 53,
1172 (
1173 Float::with_val(53, 3.3219280948873626),
1174 Float::with_val(53, 0.0),
1175 ),
1176 ))
1177 .unwrap();
1178 assert_eq!(value.clone().log2(), expected_result);
1179 assert_eq!(value.try_log2().unwrap(), expected_result);
1180 }
1181
1182 #[test]
1183 fn test_complex_log2_zero() {
1184 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1185 53,
1186 (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
1187 ))
1188 .unwrap();
1189 let result = value.try_log2();
1190 assert!(matches!(
1191 result,
1192 Err(LogarithmComplexErrors::Input {
1193 source: LogarithmComplexInputErrors::ZeroArgument { .. }
1194 })
1195 ));
1196 }
1197
1198 #[test]
1199 fn test_complex_log2_negative() {
1200 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1201 53,
1202 (Float::with_val(53, -10.0), Float::with_val(53, 0.0)),
1203 ))
1204 .unwrap();
1205 let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1206 53,
1207 (
1208 Float::with_val(53, 3.3219280948873626),
1209 Float::with_val(53, 4.532360141827194),
1210 ),
1211 ))
1212 .unwrap();
1213 assert_eq!(value.clone().log2(), expected_result);
1214 assert_eq!(value.try_log2().unwrap(), expected_result);
1215 }
1216
1217 #[test]
1218 fn test_complex_log2_one() {
1219 let value = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1220 53,
1221 (Float::with_val(53, 1.0), Float::with_val(53, 0.0)),
1222 ))
1223 .unwrap();
1224 let expected_result = ComplexRugStrictFinite::<53>::try_new(Complex::with_val(
1225 53,
1226 (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
1227 ))
1228 .unwrap();
1229 assert_eq!(value.clone().log2(), expected_result);
1230 assert_eq!(value.try_log2().unwrap(), expected_result);
1231 }
1232 }
1233 }
1234 }
1235}
1236