// Copyright © 2024 Mikhail Hogrefe // // This file is part of Malachite. // // Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU // Lesser General Public License (LGPL) as published by the Free Software Foundation; either version // 3 of the License, or (at your option) any later version. See . use malachite_base::num::basic::floats::PrimitiveFloat; use malachite_base::num::basic::signeds::PrimitiveSigned; use malachite_base::num::basic::traits::NegativeInfinity; use malachite_base::num::basic::unsigneds::PrimitiveUnsigned; use malachite_base::num::conversion::from::{ PrimitiveFloatFromSignedError, PrimitiveFloatFromUnsignedError, SignedFromFloatError, UnsignedFromFloatError, }; use malachite_base::num::conversion::traits::{ConvertibleFrom, ExactFrom, RoundingFrom}; use malachite_base::num::float::NiceFloat; use malachite_base::rounding_modes::RoundingMode::*; use malachite_base::test_util::generators::{ primitive_float_gen, primitive_float_gen_var_13, primitive_float_gen_var_14, signed_gen, signed_gen_var_7, unsigned_gen, unsigned_gen_var_18, }; use std::fmt::Debug; use std::panic::catch_unwind; #[allow(clippy::needless_pass_by_value)] #[test] pub fn test_try_from() { fn test_double_primitive_int< T: PrimitiveFloat, U: TryFrom, Error = E> + Copy + Debug + Eq, E: Debug + Eq, >( n_in: T, n_out: Result, ) { assert_eq!(U::try_from(NiceFloat(n_in)), n_out); } test_double_primitive_int::<_, u8, _>(0.0f32, Ok(0)); test_double_primitive_int::<_, u8, _>(-0.0f32, Ok(0)); test_double_primitive_int::<_, u8, _>(123.0f32, Ok(123)); test_double_primitive_int::<_, i8, _>(-123.0f32, Ok(-123)); test_double_primitive_int::<_, u8, _>(-123.0f32, Err(UnsignedFromFloatError::FloatNegative)); test_double_primitive_int::<_, u8, _>( 500.0f32, Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange), ); test_double_primitive_int::<_, u8, _>( 123.1f32, Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange), ); test_double_primitive_int::<_, u8, _>( f32::NAN, Err(UnsignedFromFloatError::FloatInfiniteOrNan), ); test_double_primitive_int::<_, u8, _>( f32::INFINITY, Err(UnsignedFromFloatError::FloatInfiniteOrNan), ); test_double_primitive_int::<_, u8, _>( f32::NEGATIVE_INFINITY, Err(UnsignedFromFloatError::FloatInfiniteOrNan), ); test_double_primitive_int::<_, u8, _>(255.0f32, Ok(255)); test_double_primitive_int::<_, u8, _>( 256.0f32, Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange), ); test_double_primitive_int::<_, i8, _>(127.0f32, Ok(127)); test_double_primitive_int::<_, i8, _>( 128.0f32, Err(SignedFromFloatError::FloatNonIntegerOrOutOfRange), ); test_double_primitive_int::<_, i8, _>(-128.0f32, Ok(-128)); test_double_primitive_int::<_, i8, _>( -129.0f32, Err(SignedFromFloatError::FloatNonIntegerOrOutOfRange), ); fn test_double_primitive_float( n_in: T, n_out: Result, ) where NiceFloat: TryFrom, { assert_eq!(NiceFloat::::try_from(n_in), n_out.map(NiceFloat)); } test_double_primitive_float::<_, f32, _>(0u8, Ok(0.0)); test_double_primitive_float::<_, f32, _>(123u8, Ok(123.0)); test_double_primitive_float::<_, f32, _>(-123i8, Ok(-123.0)); test_double_primitive_float::<_, f32, _>(u128::MAX, Err(PrimitiveFloatFromUnsignedError)); test_double_primitive_float::<_, f32, _>(i128::MIN, Ok(-1.7014118e38)); test_double_primitive_float::<_, f32, _>(i128::MIN + 1, Err(PrimitiveFloatFromSignedError)); test_double_primitive_float::<_, f32, _>(u32::MAX, Err(PrimitiveFloatFromUnsignedError)); test_double_primitive_float::<_, f32, _>(i32::MIN, Ok(-2147483600.0)); test_double_primitive_float::<_, f32, _>(i32::MIN + 1, Err(PrimitiveFloatFromSignedError)); } #[test] pub fn test_exact_from() { fn test_single>(n: T) { assert_eq!(T::exact_from(n), n); } test_single(0u8); test_single(5u64); test_single(1000u32); test_single(123u8); test_single(-123i16); test_single(i64::MIN); test_single(usize::MAX); fn test_double_primitive_int< T: PrimitiveFloat, U: Copy + Debug + Eq + TryFrom>, >( n_in: T, n_out: U, ) { assert_eq!(U::exact_from(NiceFloat(n_in)), n_out); } test_double_primitive_int(0.0f32, 0u8); test_double_primitive_int(-0.0f32, 0u8); test_double_primitive_int(123.0f32, 123u8); test_double_primitive_int(-123.0f32, -123i8); test_double_primitive_int(255.0f32, 255u8); test_double_primitive_int(127.0f32, 127i8); test_double_primitive_int(-128.0f32, -128i8); fn test_double_primitive_float(n_in: T, n_out: U) where NiceFloat: TryFrom, { assert_eq!(NiceFloat::::exact_from(n_in), NiceFloat(n_out)); } test_double_primitive_float(0u8, 0.0f32); test_double_primitive_float(123u8, 123.0f32); test_double_primitive_float(-123i8, -123.0f32); test_double_primitive_float(i128::MIN, -1.7014118e38f32); test_double_primitive_float(i32::MIN, -2147483600.0f32); } #[test] fn exact_from_fail() { assert_panic!(u32::exact_from(-1i8)); assert_panic!(u16::exact_from(u32::MAX)); assert_panic!(u32::exact_from(i32::MIN)); assert_panic!(u16::exact_from(i32::MIN)); assert_panic!(i16::exact_from(i32::MIN)); assert_panic!(u32::exact_from(-5i32)); assert_panic!(i32::exact_from(3000000000u32)); assert_panic!(i8::exact_from(-1000i16)); assert_panic!(u8::exact_from(NiceFloat(-123.0f32))); assert_panic!(u8::exact_from(NiceFloat(500.0f32))); assert_panic!(u8::exact_from(NiceFloat(123.1f32))); assert_panic!(u8::exact_from(NiceFloat(f32::NAN))); assert_panic!(u8::exact_from(NiceFloat(f32::INFINITY))); assert_panic!(u8::exact_from(NiceFloat(f32::NEGATIVE_INFINITY))); assert_panic!(u8::exact_from(NiceFloat(256.0f32))); assert_panic!(i8::exact_from(NiceFloat(128.0f32))); assert_panic!(i8::exact_from(NiceFloat(-129.0f32))); assert_panic!(NiceFloat::::exact_from(u128::MAX)); assert_panic!(NiceFloat::::exact_from(i128::MIN + 1)); assert_panic!(NiceFloat::::exact_from(u32::MAX)); assert_panic!(NiceFloat::::exact_from(i32::MIN + 1)); } fn try_from_and_exact_from_helper_unsigned_primitive_float< T: TryFrom, Error = UnsignedFromFloatError> + PrimitiveUnsigned + RoundingFrom, U: PrimitiveFloat + RoundingFrom, >() where NiceFloat: TryFrom, { primitive_float_gen::().test_properties(|f| { let f = NiceFloat(f); let result = T::try_from(f); if let Ok(u) = result { assert_eq!(u, T::exact_from(f)); assert_eq!( NiceFloat(f.0.abs_negative_zero()), NiceFloat::::exact_from(u) ); } }); primitive_float_gen_var_13::().test_properties(|f| { let f = NiceFloat(f); let u = T::exact_from(f); assert_eq!(NiceFloat::::exact_from(u), f); assert_eq!(T::try_from(f).unwrap(), u); assert_eq!(T::rounding_from(f.0, Exact).0, u); }); } fn try_from_and_exact_from_helper_signed_primitive_float< T: TryFrom, Error = SignedFromFloatError> + PrimitiveSigned + RoundingFrom, U: PrimitiveFloat + RoundingFrom, >() where NiceFloat: TryFrom, { primitive_float_gen::().test_properties(|f| { let f = NiceFloat(f); let result = T::try_from(f); if let Ok(i) = result { assert_eq!(i, T::exact_from(f)); assert_eq!( NiceFloat(f.0.abs_negative_zero()), NiceFloat::::exact_from(i) ); } }); primitive_float_gen_var_14::().test_properties(|f| { let f = NiceFloat(f); let i = T::exact_from(f); assert_eq!(NiceFloat::::exact_from(i), f); assert_eq!(T::try_from(f).unwrap(), i); assert_eq!(T::rounding_from(f.0, Exact).0, i); }); } fn try_from_and_exact_from_helper_primitive_float_unsigned< T: ConvertibleFrom + PrimitiveFloat + RoundingFrom, U: PrimitiveUnsigned + RoundingFrom + TryFrom>, >() where NiceFloat: TryFrom, { unsigned_gen::().test_properties(|u| { let result = NiceFloat::::try_from(u); if let Ok(f) = result { assert_eq!(f, NiceFloat::::exact_from(u)); assert_eq!(u, U::exact_from(f)); } }); unsigned_gen_var_18::().test_properties(|u| { let f = NiceFloat::::exact_from(u); assert_eq!(U::exact_from(f), u); assert_eq!(NiceFloat::::try_from(u).unwrap(), f); assert_eq!(NiceFloat(T::rounding_from(u, Exact).0), f); }); } fn try_from_and_exact_from_helper_primitive_float_signed< T: ConvertibleFrom + PrimitiveFloat + RoundingFrom, U: PrimitiveSigned + RoundingFrom + TryFrom>, >() where NiceFloat: TryFrom, { signed_gen::().test_properties(|i| { let result = NiceFloat::::try_from(i); if let Ok(f) = result { assert_eq!(f, NiceFloat::::exact_from(i)); assert_eq!(i, U::exact_from(f)); } }); signed_gen_var_7::().test_properties(|i| { let f = NiceFloat::::exact_from(i); assert_eq!(U::exact_from(f), i); assert_eq!(NiceFloat::::try_from(i).unwrap(), f); assert_eq!(NiceFloat(T::rounding_from(i, Exact).0), f); }); } #[test] fn try_from_and_exact_from_properties() { apply_fn_to_unsigneds_and_primitive_floats!( try_from_and_exact_from_helper_unsigned_primitive_float ); apply_fn_to_signeds_and_primitive_floats!( try_from_and_exact_from_helper_signed_primitive_float ); apply_fn_to_primitive_floats_and_unsigneds!( try_from_and_exact_from_helper_primitive_float_unsigned ); apply_fn_to_primitive_floats_and_signeds!( try_from_and_exact_from_helper_primitive_float_signed ); }