// 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::named::Named; use malachite_base::num::arithmetic::traits::PowerOf2; use malachite_base::num::basic::integers::PrimitiveInt; use malachite_base::num::basic::signeds::PrimitiveSigned; use malachite_base::num::basic::unsigneds::PrimitiveUnsigned; use malachite_base::num::comparison::traits::PartialOrdAbs; use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom}; use malachite_base::rounding_modes::RoundingMode::{self, *}; use malachite_base::test_util::generators::{ signed_gen, signed_gen_var_5, signed_pair_gen_var_2, signed_unsigned_pair_gen_var_20, unsigned_gen, unsigned_pair_gen_var_32, unsigned_signed_pair_gen_var_1, }; use malachite_float::test_util::common::{rug_round_try_from_rounding_mode, to_hex_string}; use malachite_float::test_util::generators::*; use malachite_float::{ComparableFloat, ComparableFloatRef, Float}; use malachite_nz::integer::Integer; use malachite_nz::natural::Natural; use malachite_nz::platform::{Limb, SignedLimb}; use malachite_q::Rational; use rug::float::Round; use rug::ops::AssignRound; use rug::Assign; use std::cmp::max; use std::cmp::Ordering::{self, *}; use std::panic::catch_unwind; #[test] fn test_from_primitive_int() { fn test_helper(u: T, out: &str, out_hex: &str) where Float: From, rug::Float: Assign, Limb: WrappingFrom, SignedLimb: WrappingFrom, { let x = Float::from(u); assert!(x.is_valid()); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); let rug_x = rug::Float::with_val(max(1, u32::exact_from(u.significant_bits())), u); let x = Float::exact_from(&rug_x); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); if T::NAME == Limb::NAME { let x_alt = Float::const_from_unsigned(Limb::wrapping_from(u)); assert!(x_alt.is_valid()); assert_eq!(ComparableFloatRef(&x_alt), ComparableFloatRef(&x)); } if T::NAME == SignedLimb::NAME { let x_alt = Float::const_from_signed(SignedLimb::wrapping_from(u)); assert!(x_alt.is_valid()); assert_eq!(ComparableFloat(x_alt), ComparableFloat(x)); } } fn test_helper_ui() where Float: From, rug::Float: Assign, Limb: WrappingFrom, SignedLimb: WrappingFrom, { test_helper(T::ZERO, "0.0", "0x0.0"); test_helper(T::ONE, "1.0", "0x1.0#1"); test_helper(T::exact_from(123u8), "123.0", "0x7b.0#7"); } apply_fn_to_primitive_ints!(test_helper_ui); test_helper(1000000000000u64, "1000000000000.0", "0xe8d4a51000.0#40"); fn test_helper_i() where Float: From, rug::Float: Assign, Limb: WrappingFrom, SignedLimb: WrappingFrom, { test_helper(T::NEGATIVE_ONE, "-1.0", "-0x1.0#1"); test_helper(T::from(-123i8), "-123.0", "-0x7b.0#7"); } apply_fn_to_signeds!(test_helper_i); test_helper(-1000000000000i64, "-1000000000000.0", "-0xe8d4a51000.0#40"); } #[test] fn test_from_primitive_int_prec() { fn test_helper_u( u: T, prec: u64, out: &str, out_hex: &str, out_o: Ordering, ) where Natural: From, rug::Float: Assign, { let (x, o) = Float::from_unsigned_prec(u, prec); assert!(x.is_valid()); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); assert_eq!(o, out_o); let rug_x = rug::Float::with_val(u32::exact_from(prec), u); let x = Float::exact_from(&rug_x); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); } fn test_helper_u2() where Natural: From, rug::Float: Assign, { test_helper_u(T::ZERO, 1, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 10, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 20, "0.0", "0x0.0", Equal); test_helper_u(T::ONE, 1, "1.0", "0x1.0#1", Equal); test_helper_u(T::ONE, 10, "1.0", "0x1.000#10", Equal); test_helper_u(T::ONE, 20, "1.0", "0x1.00000#20", Equal); test_helper_u(T::from(123u8), 1, "1.0e2", "0x8.0E+1#1", Greater); test_helper_u(T::from(123u8), 10, "123.0", "0x7b.0#10", Equal); test_helper_u(T::from(123u8), 20, "123.0", "0x7b.0000#20", Equal); } apply_fn_to_unsigneds!(test_helper_u2); test_helper_u(1000000000000u64, 1, "1.0e12", "0x1.0E+10#1", Greater); test_helper_u(1000000000000u64, 10, "9.997e11", "0xe.8cE+9#10", Less); test_helper_u(1000000000000u64, 20, "9.999997e11", "0xe.8d4aE+9#20", Less); fn test_helper_i(u: T, prec: u64, out: &str, out_hex: &str, out_o: Ordering) where Integer: From, rug::Float: Assign, { let (x, o) = Float::from_signed_prec(u, prec); assert!(x.is_valid()); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); assert_eq!(o, out_o); let rug_x = rug::Float::with_val(u32::exact_from(prec), u); let x = Float::exact_from(&rug_x); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); } fn test_helper_i2() where Integer: From, rug::Float: Assign, { test_helper_i(T::ZERO, 1, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 10, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 20, "0.0", "0x0.0", Equal); test_helper_i(T::ONE, 1, "1.0", "0x1.0#1", Equal); test_helper_i(T::ONE, 10, "1.0", "0x1.000#10", Equal); test_helper_i(T::ONE, 20, "1.0", "0x1.00000#20", Equal); test_helper_i(T::from(123i8), 1, "1.0e2", "0x8.0E+1#1", Greater); test_helper_i(T::from(123i8), 10, "123.0", "0x7b.0#10", Equal); test_helper_i(T::from(123i8), 20, "123.0", "0x7b.0000#20", Equal); test_helper_i(T::NEGATIVE_ONE, 1, "-1.0", "-0x1.0#1", Equal); test_helper_i(T::NEGATIVE_ONE, 10, "-1.0", "-0x1.000#10", Equal); test_helper_i(T::NEGATIVE_ONE, 20, "-1.0", "-0x1.00000#20", Equal); test_helper_i(T::from(-123i8), 1, "-1.0e2", "-0x8.0E+1#1", Less); test_helper_i(T::from(-123i8), 10, "-123.0", "-0x7b.0#10", Equal); test_helper_i(T::from(-123i8), 20, "-123.0", "-0x7b.0000#20", Equal); } apply_fn_to_signeds!(test_helper_i2); test_helper_i(1000000000000i64, 1, "1.0e12", "0x1.0E+10#1", Greater); test_helper_i(1000000000000i64, 10, "9.997e11", "0xe.8cE+9#10", Less); test_helper_i(1000000000000i64, 20, "9.999997e11", "0xe.8d4aE+9#20", Less); test_helper_i(-1000000000000i64, 1, "-1.0e12", "-0x1.0E+10#1", Less); test_helper_i(-1000000000000i64, 10, "-9.997e11", "-0xe.8cE+9#10", Greater); test_helper_i( -1000000000000i64, 20, "-9.999997e11", "-0xe.8d4aE+9#20", Greater, ); } fn from_unsigned_prec_fail_helper() where Natural: From, { assert_panic!(Float::from_unsigned_prec(T::ZERO, 0)); assert_panic!(Float::from_unsigned_prec(T::ONE, 0)); } fn from_signed_prec_fail_helper() where Integer: From, { assert_panic!(Float::from_signed_prec(T::ZERO, 0)); assert_panic!(Float::from_signed_prec(T::ONE, 0)); assert_panic!(Float::from_signed_prec(T::NEGATIVE_ONE, 0)); } #[test] fn from_primitive_int_prec_fail() { apply_fn_to_unsigneds!(from_unsigned_prec_fail_helper); apply_fn_to_signeds!(from_signed_prec_fail_helper); } #[test] fn test_from_primitive_int_prec_round() { fn test_helper_u( u: T, prec: u64, rm: RoundingMode, out: &str, out_hex: &str, out_o: Ordering, ) where Natural: From, rug::Float: AssignRound, { let (x, o) = Float::from_unsigned_prec_round(u, prec, rm); assert!(x.is_valid()); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); assert_eq!(o, out_o); if let Ok(rm) = rug_round_try_from_rounding_mode(rm) { let (rug_x, rug_o) = rug::Float::with_val_round(u32::exact_from(prec), u, rm); let x = Float::exact_from(&rug_x); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); assert_eq!(rug_o, out_o); } } fn test_helper_u2() where Natural: From, rug::Float: AssignRound, { test_helper_u(T::ZERO, 1, Floor, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 1, Ceiling, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 1, Down, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 1, Up, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 1, Nearest, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 1, Exact, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 10, Floor, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 10, Ceiling, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 10, Down, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 10, Up, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 10, Nearest, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 10, Exact, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 20, Floor, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 20, Ceiling, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 20, Down, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 20, Up, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 20, Nearest, "0.0", "0x0.0", Equal); test_helper_u(T::ZERO, 20, Exact, "0.0", "0x0.0", Equal); test_helper_u(T::ONE, 1, Floor, "1.0", "0x1.0#1", Equal); test_helper_u(T::ONE, 1, Ceiling, "1.0", "0x1.0#1", Equal); test_helper_u(T::ONE, 1, Down, "1.0", "0x1.0#1", Equal); test_helper_u(T::ONE, 1, Up, "1.0", "0x1.0#1", Equal); test_helper_u(T::ONE, 1, Nearest, "1.0", "0x1.0#1", Equal); test_helper_u(T::ONE, 1, Exact, "1.0", "0x1.0#1", Equal); test_helper_u(T::ONE, 10, Floor, "1.0", "0x1.000#10", Equal); test_helper_u(T::ONE, 10, Ceiling, "1.0", "0x1.000#10", Equal); test_helper_u(T::ONE, 10, Down, "1.0", "0x1.000#10", Equal); test_helper_u(T::ONE, 10, Up, "1.0", "0x1.000#10", Equal); test_helper_u(T::ONE, 10, Nearest, "1.0", "0x1.000#10", Equal); test_helper_u(T::ONE, 10, Exact, "1.0", "0x1.000#10", Equal); test_helper_u(T::ONE, 20, Floor, "1.0", "0x1.00000#20", Equal); test_helper_u(T::ONE, 20, Ceiling, "1.0", "0x1.00000#20", Equal); test_helper_u(T::ONE, 20, Down, "1.0", "0x1.00000#20", Equal); test_helper_u(T::ONE, 20, Up, "1.0", "0x1.00000#20", Equal); test_helper_u(T::ONE, 20, Nearest, "1.0", "0x1.00000#20", Equal); test_helper_u(T::ONE, 20, Exact, "1.0", "0x1.00000#20", Equal); test_helper_u(T::from(123u8), 1, Floor, "6.0e1", "0x4.0E+1#1", Less); test_helper_u(T::from(123u8), 1, Ceiling, "1.0e2", "0x8.0E+1#1", Greater); test_helper_u(T::from(123u8), 1, Down, "6.0e1", "0x4.0E+1#1", Less); test_helper_u(T::from(123u8), 1, Up, "1.0e2", "0x8.0E+1#1", Greater); test_helper_u(T::from(123u8), 1, Nearest, "1.0e2", "0x8.0E+1#1", Greater); test_helper_u(T::from(123u8), 10, Floor, "123.0", "0x7b.0#10", Equal); test_helper_u(T::from(123u8), 10, Ceiling, "123.0", "0x7b.0#10", Equal); test_helper_u(T::from(123u8), 10, Down, "123.0", "0x7b.0#10", Equal); test_helper_u(T::from(123u8), 10, Up, "123.0", "0x7b.0#10", Equal); test_helper_u(T::from(123u8), 10, Nearest, "123.0", "0x7b.0#10", Equal); test_helper_u(T::from(123u8), 10, Exact, "123.0", "0x7b.0#10", Equal); test_helper_u(T::from(123u8), 20, Floor, "123.0", "0x7b.0000#20", Equal); test_helper_u(T::from(123u8), 20, Ceiling, "123.0", "0x7b.0000#20", Equal); test_helper_u(T::from(123u8), 20, Down, "123.0", "0x7b.0000#20", Equal); test_helper_u(T::from(123u8), 20, Up, "123.0", "0x7b.0000#20", Equal); test_helper_u(T::from(123u8), 20, Nearest, "123.0", "0x7b.0000#20", Equal); test_helper_u(T::from(123u8), 20, Exact, "123.0", "0x7b.0000#20", Equal); } apply_fn_to_unsigneds!(test_helper_u2); test_helper_u(1000000000000u64, 1, Floor, "5.0e11", "0x8.0E+9#1", Less); test_helper_u( 1000000000000u64, 1, Ceiling, "1.0e12", "0x1.0E+10#1", Greater, ); test_helper_u(1000000000000u64, 1, Down, "5.0e11", "0x8.0E+9#1", Less); test_helper_u(1000000000000u64, 1, Up, "1.0e12", "0x1.0E+10#1", Greater); test_helper_u( 1000000000000u64, 1, Nearest, "1.0e12", "0x1.0E+10#1", Greater, ); test_helper_u( 1000000000000u64, 10, Floor, "9.997e11", "0xe.8cE+9#10", Less, ); test_helper_u( 1000000000000u64, 10, Ceiling, "1.001e12", "0xe.90E+9#10", Greater, ); test_helper_u(1000000000000u64, 10, Down, "9.997e11", "0xe.8cE+9#10", Less); test_helper_u( 1000000000000u64, 10, Up, "1.001e12", "0xe.90E+9#10", Greater, ); test_helper_u( 1000000000000u64, 10, Nearest, "9.997e11", "0xe.8cE+9#10", Less, ); test_helper_u( 1000000000000u64, 20, Floor, "9.999997e11", "0xe.8d4aE+9#20", Less, ); test_helper_u( 1000000000000u64, 20, Ceiling, "1.000001e12", "0xe.8d4bE+9#20", Greater, ); test_helper_u( 1000000000000u64, 20, Down, "9.999997e11", "0xe.8d4aE+9#20", Less, ); test_helper_u( 1000000000000u64, 20, Up, "1.000001e12", "0xe.8d4bE+9#20", Greater, ); test_helper_u( 1000000000000u64, 20, Nearest, "9.999997e11", "0xe.8d4aE+9#20", Less, ); fn test_helper_i( u: T, prec: u64, rm: RoundingMode, out: &str, out_hex: &str, out_o: Ordering, ) where Integer: From, rug::Float: AssignRound, { let (x, o) = Float::from_signed_prec_round(u, prec, rm); assert!(x.is_valid()); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); assert_eq!(o, out_o); if let Ok(rm) = rug_round_try_from_rounding_mode(rm) { let (rug_x, rug_o) = rug::Float::with_val_round(u32::exact_from(prec), u, rm); let x = Float::exact_from(&rug_x); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); assert_eq!(rug_o, out_o); } } fn test_helper_i2() where Integer: From, rug::Float: AssignRound, { test_helper_i(T::ZERO, 1, Floor, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 1, Ceiling, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 1, Down, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 1, Up, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 1, Nearest, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 1, Exact, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 10, Floor, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 10, Ceiling, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 10, Down, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 10, Up, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 10, Nearest, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 10, Exact, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 20, Floor, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 20, Ceiling, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 20, Down, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 20, Up, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 20, Nearest, "0.0", "0x0.0", Equal); test_helper_i(T::ZERO, 20, Exact, "0.0", "0x0.0", Equal); test_helper_i(T::ONE, 1, Floor, "1.0", "0x1.0#1", Equal); test_helper_i(T::ONE, 1, Ceiling, "1.0", "0x1.0#1", Equal); test_helper_i(T::ONE, 1, Down, "1.0", "0x1.0#1", Equal); test_helper_i(T::ONE, 1, Up, "1.0", "0x1.0#1", Equal); test_helper_i(T::ONE, 1, Nearest, "1.0", "0x1.0#1", Equal); test_helper_i(T::ONE, 1, Exact, "1.0", "0x1.0#1", Equal); test_helper_i(T::ONE, 10, Floor, "1.0", "0x1.000#10", Equal); test_helper_i(T::ONE, 10, Ceiling, "1.0", "0x1.000#10", Equal); test_helper_i(T::ONE, 10, Down, "1.0", "0x1.000#10", Equal); test_helper_i(T::ONE, 10, Up, "1.0", "0x1.000#10", Equal); test_helper_i(T::ONE, 10, Nearest, "1.0", "0x1.000#10", Equal); test_helper_i(T::ONE, 10, Exact, "1.0", "0x1.000#10", Equal); test_helper_i(T::ONE, 20, Floor, "1.0", "0x1.00000#20", Equal); test_helper_i(T::ONE, 20, Ceiling, "1.0", "0x1.00000#20", Equal); test_helper_i(T::ONE, 20, Down, "1.0", "0x1.00000#20", Equal); test_helper_i(T::ONE, 20, Up, "1.0", "0x1.00000#20", Equal); test_helper_i(T::ONE, 20, Nearest, "1.0", "0x1.00000#20", Equal); test_helper_i(T::ONE, 20, Exact, "1.0", "0x1.00000#20", Equal); test_helper_i(T::from(123i8), 1, Floor, "6.0e1", "0x4.0E+1#1", Less); test_helper_i(T::from(123i8), 1, Ceiling, "1.0e2", "0x8.0E+1#1", Greater); test_helper_i(T::from(123i8), 1, Down, "6.0e1", "0x4.0E+1#1", Less); test_helper_i(T::from(123i8), 1, Up, "1.0e2", "0x8.0E+1#1", Greater); test_helper_i(T::from(123i8), 1, Nearest, "1.0e2", "0x8.0E+1#1", Greater); test_helper_i(T::from(123i8), 10, Floor, "123.0", "0x7b.0#10", Equal); test_helper_i(T::from(123i8), 10, Ceiling, "123.0", "0x7b.0#10", Equal); test_helper_i(T::from(123i8), 10, Down, "123.0", "0x7b.0#10", Equal); test_helper_i(T::from(123i8), 10, Up, "123.0", "0x7b.0#10", Equal); test_helper_i(T::from(123i8), 10, Nearest, "123.0", "0x7b.0#10", Equal); test_helper_i(T::from(123i8), 10, Exact, "123.0", "0x7b.0#10", Equal); test_helper_i(T::from(123i8), 20, Floor, "123.0", "0x7b.0000#20", Equal); test_helper_i(T::from(123i8), 20, Ceiling, "123.0", "0x7b.0000#20", Equal); test_helper_i(T::from(123i8), 20, Down, "123.0", "0x7b.0000#20", Equal); test_helper_i(T::from(123i8), 20, Up, "123.0", "0x7b.0000#20", Equal); test_helper_i(T::from(123i8), 20, Nearest, "123.0", "0x7b.0000#20", Equal); test_helper_i(T::from(123i8), 20, Exact, "123.0", "0x7b.0000#20", Equal); test_helper_i(T::NEGATIVE_ONE, 1, Floor, "-1.0", "-0x1.0#1", Equal); test_helper_i(T::NEGATIVE_ONE, 1, Ceiling, "-1.0", "-0x1.0#1", Equal); test_helper_i(T::NEGATIVE_ONE, 1, Down, "-1.0", "-0x1.0#1", Equal); test_helper_i(T::NEGATIVE_ONE, 1, Up, "-1.0", "-0x1.0#1", Equal); test_helper_i(T::NEGATIVE_ONE, 1, Nearest, "-1.0", "-0x1.0#1", Equal); test_helper_i(T::NEGATIVE_ONE, 1, Exact, "-1.0", "-0x1.0#1", Equal); test_helper_i(T::NEGATIVE_ONE, 10, Floor, "-1.0", "-0x1.000#10", Equal); test_helper_i(T::NEGATIVE_ONE, 10, Ceiling, "-1.0", "-0x1.000#10", Equal); test_helper_i(T::NEGATIVE_ONE, 10, Down, "-1.0", "-0x1.000#10", Equal); test_helper_i(T::NEGATIVE_ONE, 10, Up, "-1.0", "-0x1.000#10", Equal); test_helper_i(T::NEGATIVE_ONE, 10, Nearest, "-1.0", "-0x1.000#10", Equal); test_helper_i(T::NEGATIVE_ONE, 10, Exact, "-1.0", "-0x1.000#10", Equal); test_helper_i(T::NEGATIVE_ONE, 20, Floor, "-1.0", "-0x1.00000#20", Equal); test_helper_i(T::NEGATIVE_ONE, 20, Ceiling, "-1.0", "-0x1.00000#20", Equal); test_helper_i(T::NEGATIVE_ONE, 20, Down, "-1.0", "-0x1.00000#20", Equal); test_helper_i(T::NEGATIVE_ONE, 20, Up, "-1.0", "-0x1.00000#20", Equal); test_helper_i(T::NEGATIVE_ONE, 20, Nearest, "-1.0", "-0x1.00000#20", Equal); test_helper_i(T::NEGATIVE_ONE, 20, Exact, "-1.0", "-0x1.00000#20", Equal); test_helper_i(T::from(-123i8), 1, Floor, "-1.0e2", "-0x8.0E+1#1", Less); test_helper_i( T::from(-123i8), 1, Ceiling, "-6.0e1", "-0x4.0E+1#1", Greater, ); test_helper_i(T::from(-123i8), 1, Down, "-6.0e1", "-0x4.0E+1#1", Greater); test_helper_i(T::from(-123i8), 1, Up, "-1.0e2", "-0x8.0E+1#1", Less); test_helper_i(T::from(-123i8), 1, Nearest, "-1.0e2", "-0x8.0E+1#1", Less); test_helper_i(T::from(-123i8), 10, Floor, "-123.0", "-0x7b.0#10", Equal); test_helper_i(T::from(-123i8), 10, Ceiling, "-123.0", "-0x7b.0#10", Equal); test_helper_i(T::from(-123i8), 10, Down, "-123.0", "-0x7b.0#10", Equal); test_helper_i(T::from(-123i8), 10, Up, "-123.0", "-0x7b.0#10", Equal); test_helper_i(T::from(-123i8), 10, Nearest, "-123.0", "-0x7b.0#10", Equal); test_helper_i(T::from(-123i8), 10, Exact, "-123.0", "-0x7b.0#10", Equal); test_helper_i(T::from(-123i8), 20, Floor, "-123.0", "-0x7b.0000#20", Equal); test_helper_i( T::from(-123i8), 20, Ceiling, "-123.0", "-0x7b.0000#20", Equal, ); test_helper_i(T::from(-123i8), 20, Down, "-123.0", "-0x7b.0000#20", Equal); test_helper_i(T::from(-123i8), 20, Up, "-123.0", "-0x7b.0000#20", Equal); test_helper_i( T::from(-123i8), 20, Nearest, "-123.0", "-0x7b.0000#20", Equal, ); test_helper_i(T::from(-123i8), 20, Exact, "-123.0", "-0x7b.0000#20", Equal); } apply_fn_to_signeds!(test_helper_i2); test_helper_i(1000000000000i64, 1, Floor, "5.0e11", "0x8.0E+9#1", Less); test_helper_i( 1000000000000i64, 1, Ceiling, "1.0e12", "0x1.0E+10#1", Greater, ); test_helper_i(1000000000000i64, 1, Down, "5.0e11", "0x8.0E+9#1", Less); test_helper_i(1000000000000i64, 1, Up, "1.0e12", "0x1.0E+10#1", Greater); test_helper_i( 1000000000000i64, 1, Nearest, "1.0e12", "0x1.0E+10#1", Greater, ); test_helper_i( 1000000000000i64, 10, Floor, "9.997e11", "0xe.8cE+9#10", Less, ); test_helper_i( 1000000000000i64, 10, Ceiling, "1.001e12", "0xe.90E+9#10", Greater, ); test_helper_i(1000000000000i64, 10, Down, "9.997e11", "0xe.8cE+9#10", Less); test_helper_i( 1000000000000i64, 10, Up, "1.001e12", "0xe.90E+9#10", Greater, ); test_helper_i( 1000000000000i64, 10, Nearest, "9.997e11", "0xe.8cE+9#10", Less, ); test_helper_i( 1000000000000i64, 20, Floor, "9.999997e11", "0xe.8d4aE+9#20", Less, ); test_helper_i( 1000000000000i64, 20, Ceiling, "1.000001e12", "0xe.8d4bE+9#20", Greater, ); test_helper_i( 1000000000000i64, 20, Down, "9.999997e11", "0xe.8d4aE+9#20", Less, ); test_helper_i( 1000000000000i64, 20, Up, "1.000001e12", "0xe.8d4bE+9#20", Greater, ); test_helper_i( 1000000000000i64, 20, Nearest, "9.999997e11", "0xe.8d4aE+9#20", Less, ); test_helper_i(-1000000000000i64, 1, Floor, "-1.0e12", "-0x1.0E+10#1", Less); test_helper_i( -1000000000000i64, 1, Ceiling, "-5.0e11", "-0x8.0E+9#1", Greater, ); test_helper_i( -1000000000000i64, 1, Down, "-5.0e11", "-0x8.0E+9#1", Greater, ); test_helper_i(-1000000000000i64, 1, Up, "-1.0e12", "-0x1.0E+10#1", Less); test_helper_i( -1000000000000i64, 1, Nearest, "-1.0e12", "-0x1.0E+10#1", Less, ); test_helper_i( -1000000000000i64, 10, Floor, "-1.001e12", "-0xe.90E+9#10", Less, ); test_helper_i( -1000000000000i64, 10, Ceiling, "-9.997e11", "-0xe.8cE+9#10", Greater, ); test_helper_i( -1000000000000i64, 10, Down, "-9.997e11", "-0xe.8cE+9#10", Greater, ); test_helper_i( -1000000000000i64, 10, Up, "-1.001e12", "-0xe.90E+9#10", Less, ); test_helper_i( -1000000000000i64, 10, Nearest, "-9.997e11", "-0xe.8cE+9#10", Greater, ); test_helper_i( -1000000000000i64, 20, Floor, "-1.000001e12", "-0xe.8d4bE+9#20", Less, ); test_helper_i( -1000000000000i64, 20, Ceiling, "-9.999997e11", "-0xe.8d4aE+9#20", Greater, ); test_helper_i( -1000000000000i64, 20, Down, "-9.999997e11", "-0xe.8d4aE+9#20", Greater, ); test_helper_i( -1000000000000i64, 20, Up, "-1.000001e12", "-0xe.8d4bE+9#20", Less, ); test_helper_i( -1000000000000i64, 20, Nearest, "-9.999997e11", "-0xe.8d4aE+9#20", Greater, ); } fn from_unsigned_prec_round_fail_helper() where Natural: From, { assert_panic!(Float::from_unsigned_prec_round(T::ZERO, 0, Floor)); assert_panic!(Float::from_unsigned_prec_round(T::ONE, 0, Floor)); assert_panic!(Float::from_unsigned_prec_round(T::from(123u8), 1, Exact)); } fn from_signed_prec_round_fail_helper() where Integer: From, { assert_panic!(Float::from_signed_prec_round(T::ZERO, 0, Floor)); assert_panic!(Float::from_signed_prec_round(T::ONE, 0, Floor)); assert_panic!(Float::from_signed_prec_round(T::from(123i8), 1, Exact)); assert_panic!(Float::from_signed_prec_round(T::NEGATIVE_ONE, 0, Floor)); assert_panic!(Float::from_signed_prec_round(T::from(-123i8), 1, Exact)); } #[test] fn from_primitive_int_prec_round_fail() { apply_fn_to_unsigneds!(from_unsigned_prec_round_fail_helper); apply_fn_to_signeds!(from_signed_prec_round_fail_helper); } #[test] fn test_const_from_unsigned_times_power_of_2() { fn test_helper(u: Limb, pow: i32, out: &str, out_hex: &str) { let x = Float::const_from_unsigned_times_power_of_2(u, pow); assert!(x.is_valid()); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); } test_helper(0, 0, "0.0", "0x0.0"); test_helper(0, 10, "0.0", "0x0.0"); test_helper(0, -10, "0.0", "0x0.0"); test_helper(1, 0, "1.0", "0x1.0#1"); test_helper(1, 10, "1.0e3", "0x4.0E+2#1"); test_helper(1, -10, "0.001", "0x0.004#1"); #[cfg(not(feature = "32_bit_limbs"))] { test_helper( 884279719003555, -48, "3.141592653589793", "0x3.243f6a8885a3#50", ); } } #[test] fn test_const_from_signed_times_power_of_2() { fn test_helper(u: SignedLimb, pow: i32, out: &str, out_hex: &str) { let x = Float::const_from_signed_times_power_of_2(u, pow); assert!(x.is_valid()); assert_eq!(x.to_string(), out); assert_eq!(to_hex_string(&x), out_hex); } test_helper(0, 0, "0.0", "0x0.0"); test_helper(0, 10, "0.0", "0x0.0"); test_helper(0, -10, "0.0", "0x0.0"); test_helper(1, 0, "1.0", "0x1.0#1"); test_helper(1, 10, "1.0e3", "0x4.0E+2#1"); test_helper(1, -10, "0.001", "0x0.004#1"); test_helper(-1, 0, "-1.0", "-0x1.0#1"); test_helper(-1, 10, "-1.0e3", "-0x4.0E+2#1"); test_helper(-1, -10, "-0.001", "-0x0.004#1"); #[cfg(not(feature = "32_bit_limbs"))] { test_helper( 884279719003555, -48, "3.141592653589793", "0x3.243f6a8885a3#50", ); test_helper( -884279719003555, -48, "-3.141592653589793", "-0x3.243f6a8885a3#50", ); } } #[allow(clippy::type_repetition_in_bounds)] fn from_primitive_int_properties_helper_unsigned() where Float: From, rug::Float: Assign, Natural: From + PartialEq, for<'a> T: ExactFrom<&'a Float>, Limb: WrappingFrom, { unsigned_gen::().test_properties(|n| { let float_n = Float::from(n); assert!(float_n.is_valid()); if T::WIDTH == Limb::WIDTH { let n_alt = Float::const_from_unsigned(Limb::wrapping_from(n)); assert!(n_alt.is_valid()); assert_eq!(ComparableFloatRef(&n_alt), ComparableFloatRef(&float_n)); let n_alt = Float::const_from_unsigned_times_power_of_2(Limb::wrapping_from(n), 0); assert!(n_alt.is_valid()); assert_eq!(ComparableFloatRef(&n_alt), ComparableFloatRef(&float_n)); } let rug_n = rug::Float::with_val(max(1, u32::exact_from(n.significant_bits())), n); assert_eq!( ComparableFloatRef(&float_n), ComparableFloatRef(&From::<&rug::Float>::from(&rug_n)) ); let n_alt: Float = From::from(Natural::from(n)); assert_eq!(ComparableFloatRef(&n_alt), ComparableFloatRef(&float_n)); assert_eq!( float_n.get_prec(), if n == T::ZERO { None } else { Some(n.significant_bits()) } ); assert_eq!(T::exact_from(&float_n), n); let bits = max(1, n.significant_bits()); let (f, o) = Float::from_unsigned_prec(n, bits); assert_eq!(ComparableFloat(f), ComparableFloat(float_n)); assert_eq!(o, Equal); }); } #[allow(clippy::type_repetition_in_bounds)] fn from_primitive_int_properties_helper_signed() where Float: From, rug::Float: Assign, Integer: From + PartialEq, for<'a> T: ExactFrom<&'a Float>, SignedLimb: WrappingFrom, { signed_gen::().test_properties(|n| { let float_n = Float::from(n); assert!(float_n.is_valid()); if T::WIDTH == SignedLimb::WIDTH { let n_alt = Float::const_from_signed(SignedLimb::wrapping_from(n)); assert!(n_alt.is_valid()); assert_eq!(ComparableFloatRef(&n_alt), ComparableFloatRef(&float_n)); let n_alt = Float::const_from_signed_times_power_of_2(SignedLimb::wrapping_from(n), 0); assert!(n_alt.is_valid()); assert_eq!(ComparableFloatRef(&n_alt), ComparableFloatRef(&float_n)); } let rug_n = rug::Float::with_val(max(1, u32::exact_from(n.significant_bits())), n); assert_eq!( ComparableFloatRef(&float_n), ComparableFloatRef(&From::<&rug::Float>::from(&rug_n)) ); let n_alt: Float = From::from(Integer::from(n)); assert_eq!(ComparableFloatRef(&n_alt), ComparableFloatRef(&float_n)); assert_eq!( float_n.get_prec(), if n == T::ZERO { None } else { Some(n.significant_bits()) } ); assert_eq!(T::exact_from(&float_n), n); let bits = max(1, n.significant_bits()); let (f, o) = Float::from_signed_prec(n, bits); assert_eq!(ComparableFloat(f), ComparableFloat(float_n)); assert_eq!(o, Equal); }); } #[test] fn from_primitive_int_properties() { apply_fn_to_unsigneds!(from_primitive_int_properties_helper_unsigned); apply_fn_to_signeds!(from_primitive_int_properties_helper_signed); } fn from_primitive_int_prec_properties_helper_unsigned() where Natural: From, Float: PartialOrd, rug::Float: Assign, { unsigned_pair_gen_var_32::().test_properties(|(n, prec)| { let (float_n, o) = Float::from_unsigned_prec(n, prec); assert!(float_n.is_valid()); assert_eq!(float_n.partial_cmp(&n), Some(o)); let rug_n = rug::Float::with_val(u32::exact_from(prec), n); assert_eq!( ComparableFloatRef(&float_n), ComparableFloatRef(&Float::from(&rug_n)) ); let (float_n_alt, o_alt) = Float::from_natural_prec(Natural::from(n), prec); assert_eq!( ComparableFloatRef(&float_n_alt), ComparableFloatRef(&float_n) ); assert_eq!(o_alt, o); assert_eq!( float_n.get_prec(), if n == T::ZERO { None } else { Some(prec) } ); }); } fn from_primitive_int_prec_properties_helper_signed() where Integer: From, Float: PartialOrd, rug::Float: Assign, { signed_unsigned_pair_gen_var_20::().test_properties(|(n, prec)| { let (float_n, o) = Float::from_signed_prec(n, prec); assert!(float_n.is_valid()); assert_eq!(float_n.partial_cmp(&n), Some(o)); let rug_n = rug::Float::with_val(u32::exact_from(prec), n); assert_eq!( ComparableFloatRef(&float_n), ComparableFloatRef(&Float::from(&rug_n)) ); let (float_n_alt, o_alt) = Float::from_integer_prec(Integer::from(n), prec); assert_eq!( ComparableFloatRef(&float_n_alt), ComparableFloatRef(&float_n) ); assert_eq!(o_alt, o); assert_eq!( float_n.get_prec(), if n == T::ZERO { None } else { Some(prec) } ); }); } #[test] fn from_primitive_int_prec_properties() { apply_fn_to_unsigneds!(from_primitive_int_prec_properties_helper_unsigned); apply_fn_to_signeds!(from_primitive_int_prec_properties_helper_signed); } fn from_primitive_int_prec_round_properties_helper_unsigned() where Natural: From, Float: PartialOrd, Rational: From + PartialOrd, rug::Float: AssignRound, { unsigned_unsigned_rounding_mode_triple_gen_var_5::().test_properties(|(n, prec, rm)| { let (float_n, o) = Float::from_unsigned_prec_round(n, prec, rm); assert!(float_n.is_valid()); assert_eq!(float_n.partial_cmp(&n), Some(o)); match rm { Floor | Down => { assert_ne!(o, Greater); } Ceiling | Up => { assert_ne!(o, Less); } Exact => assert_eq!(o, Equal), _ => {} } if let Ok(rm) = rug_round_try_from_rounding_mode(rm) { let (rug_n, rug_o) = rug::Float::with_val_round(u32::exact_from(prec), n, rm); assert_eq!( ComparableFloatRef(&float_n), ComparableFloatRef(&Float::from(&rug_n)) ); assert_eq!(rug_o, o); } let (float_n_alt, o_alt) = Float::from_natural_prec_round(Natural::from(n), prec, rm); assert_eq!( ComparableFloatRef(&float_n_alt), ComparableFloatRef(&float_n) ); assert_eq!(o_alt, o); assert_eq!( float_n.get_prec(), if n == T::ZERO { None } else { Some(prec) } ); }); unsigned_pair_gen_var_32::().test_properties(|(n, prec)| { let floor = Float::from_unsigned_prec_round(n, prec, Floor); let r_floor = Rational::exact_from(&floor.0); assert!(r_floor <= n); if r_floor != T::ZERO { assert!(r_floor + Rational::exact_from(floor.0.ulp().unwrap()) > n); } let (floor_alt, floor_o_alt) = Float::from_unsigned_prec_round(n, prec, Down); assert_eq!(ComparableFloatRef(&floor_alt), ComparableFloatRef(&floor.0)); assert_eq!(floor_o_alt, floor.1); let ceiling = Float::from_unsigned_prec_round(n, prec, Ceiling); let r_ceiling = Rational::exact_from(&ceiling.0); assert!(r_ceiling >= n); if r_ceiling != T::ZERO { assert!(r_ceiling - Rational::exact_from(ceiling.0.ulp().unwrap()) < n); } let (ceiling_alt, ceiling_o_alt) = Float::from_unsigned_prec_round(n, prec, Up); assert_eq!( ComparableFloatRef(&ceiling_alt), ComparableFloatRef(&ceiling.0) ); assert_eq!(ceiling_o_alt, ceiling.1); let nearest = Float::from_unsigned_prec_round(n, prec, Nearest); assert!( ComparableFloatRef(&nearest.0) == ComparableFloatRef(&floor.0) && nearest.1 == floor.1 || ComparableFloatRef(&nearest.0) == ComparableFloatRef(&ceiling.0) && nearest.1 == ceiling.1 ); let r_nearest = Rational::exact_from(&nearest.0); if r_nearest != T::ZERO { assert!((r_nearest - Rational::from(n)) .le_abs(&(Rational::exact_from(nearest.0.ulp().unwrap()) >> 1))); } }); } fn from_primitive_int_prec_round_properties_helper_signed() where Integer: From, Float: PartialOrd, Rational: From + PartialOrd, rug::Float: AssignRound, { signed_unsigned_rounding_mode_triple_gen_var_3::().test_properties(|(n, prec, rm)| { let (float_n, o) = Float::from_signed_prec_round(n, prec, rm); assert!(float_n.is_valid()); assert_eq!(float_n.partial_cmp(&n), Some(o)); match (n >= T::ZERO, rm) { (_, Floor) | (true, Down) | (false, Up) => { assert_ne!(o, Greater); } (_, Ceiling) | (true, Up) | (false, Down) => { assert_ne!(o, Less); } (_, Exact) => assert_eq!(o, Equal), _ => {} } if let Ok(rm) = rug_round_try_from_rounding_mode(rm) { let (rug_n, rug_o) = rug::Float::with_val_round(u32::exact_from(prec), n, rm); assert_eq!( ComparableFloatRef(&float_n), ComparableFloatRef(&Float::from(&rug_n)) ); assert_eq!(rug_o, o); } let (float_n_alt, o_alt) = Float::from_integer_prec_round(Integer::from(n), prec, rm); assert_eq!( ComparableFloatRef(&float_n_alt), ComparableFloatRef(&float_n) ); assert_eq!(o_alt, o); assert_eq!( float_n.get_prec(), if n == T::ZERO { None } else { Some(prec) } ); }); signed_unsigned_pair_gen_var_20::().test_properties(|(n, prec)| { let floor = Float::from_signed_prec_round(n, prec, Floor); let r_floor = Rational::exact_from(&floor.0); assert!(r_floor <= n); if r_floor != T::ZERO { assert!(r_floor + Rational::exact_from(floor.0.ulp().unwrap()) > n); } let (floor_n_alt, o_alt) = Float::from_signed_prec_round(n, prec, if n >= T::ZERO { Down } else { Up }); assert_eq!( ComparableFloatRef(&floor_n_alt), ComparableFloatRef(&floor.0) ); assert_eq!(o_alt, floor.1); let ceiling = Float::from_signed_prec_round(n, prec, Ceiling); let r_ceiling = Rational::exact_from(&ceiling.0); assert!(r_ceiling >= n); if r_ceiling != T::ZERO { assert!(r_ceiling - Rational::exact_from(ceiling.0.ulp().unwrap()) < n); } let (ceiling_n_alt, o_alt) = Float::from_signed_prec_round(n, prec, if n >= T::ZERO { Up } else { Down }); assert_eq!( ComparableFloatRef(&ceiling_n_alt), ComparableFloatRef(&ceiling.0) ); assert_eq!(o_alt, ceiling.1); let nearest = Float::from_signed_prec_round(n, prec, Nearest); let r_nearest = Rational::exact_from(&nearest.0); assert!( ComparableFloatRef(&nearest.0) == ComparableFloatRef(&floor.0) && nearest.1 == floor.1 || ComparableFloatRef(&nearest.0) == ComparableFloatRef(&ceiling.0) && nearest.1 == ceiling.1 ); if r_nearest != T::ZERO { assert!((r_nearest - Rational::from(n)) .le_abs(&(Rational::exact_from(nearest.0.ulp().unwrap()) >> 1))); } }); } #[test] fn from_primitive_int_prec_round_properties() { apply_fn_to_unsigneds!(from_primitive_int_prec_round_properties_helper_unsigned); apply_fn_to_signeds!(from_primitive_int_prec_round_properties_helper_signed); } #[test] fn const_from_unsigned_times_power_of_2_properties() { unsigned_signed_pair_gen_var_1().test_properties(|(n, pow)| { let float_n = Float::const_from_unsigned_times_power_of_2(n, pow); assert!(float_n.is_valid()); assert!(float_n >= 0); assert_eq!( ComparableFloat(float_n), ComparableFloat(Float::from(n) << pow) ); }); signed_gen_var_5().test_properties(|pow| { assert_eq!( ComparableFloat(Float::const_from_unsigned_times_power_of_2(1, pow)), ComparableFloat(Float::power_of_2(i64::from(pow))) ); }); } #[test] fn const_from_signed_times_power_of_2_properties() { signed_pair_gen_var_2().test_properties(|(n, pow)| { let float_n = Float::const_from_signed_times_power_of_2(n, pow); assert!(float_n.is_valid()); assert_eq!(float_n >= 0, n >= 0); assert_eq!( ComparableFloat(float_n), ComparableFloat(Float::from(n) << pow) ); }); signed_gen_var_5().test_properties(|pow| { assert_eq!( ComparableFloat(Float::const_from_signed_times_power_of_2(1, pow)), ComparableFloat(Float::power_of_2(i64::from(pow))) ); }); }