// 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::arithmetic::traits::{IsPowerOf2, PowerOf2, UnsignedAbs}; use malachite_base::num::basic::signeds::PrimitiveSigned; use malachite_base::num::basic::traits::{ Infinity, NaN, NegativeInfinity, NegativeZero, One, Zero, }; use malachite_base::num::basic::unsigneds::PrimitiveUnsigned; use malachite_base::num::comparison::traits::PartialOrdAbs; use malachite_base::num::conversion::traits::ExactFrom; use malachite_base::test_util::generators::{ signed_gen, signed_gen_var_5, unsigned_gen, unsigned_gen_var_5, }; use malachite_float::test_util::common::{parse_hex_string, to_hex_string}; use malachite_float::test_util::generators::{ float_gen, float_signed_pair_gen_var_2, float_unsigned_pair_gen_var_2, }; use malachite_float::{ComparableFloat, ComparableFloatRef, Float}; use malachite_nz::integer::Integer; use std::ops::{Shl, Shr, ShrAssign}; fn test_shr_unsigned_helper(f: F) where Float: ShrAssign + Shr, for<'a> &'a Float: Shr, { let test = |s, s_hex, v: u8, out: &str, out_hex: &str| { let x = parse_hex_string(s_hex); assert_eq!(x.to_string(), s); let v = T::from(v); let mut n = x.clone(); n >>= v; assert_eq!(n.to_string(), out); assert_eq!(to_hex_string(&n), out_hex); assert!(n.is_valid()); let n = x.clone() >> v; assert_eq!(n.to_string(), out); assert!(n.is_valid()); let n = &x >> v; assert_eq!(n.to_string(), out); assert!(n.is_valid()); f(x, v, n); }; test("NaN", "NaN", 0, "NaN", "NaN"); test("NaN", "NaN", 10, "NaN", "NaN"); test("Infinity", "Infinity", 0, "Infinity", "Infinity"); test("Infinity", "Infinity", 10, "Infinity", "Infinity"); test("-Infinity", "-Infinity", 0, "-Infinity", "-Infinity"); test("-Infinity", "-Infinity", 10, "-Infinity", "-Infinity"); test("0.0", "0x0.0", 10, "0.0", "0x0.0"); test("-0.0", "-0x0.0", 10, "-0.0", "-0x0.0"); test("123.0", "0x7b.0#7", 0, "123.0", "0x7b.0#7"); test("123.0", "0x7b.0#7", 1, "61.5", "0x3d.8#7"); test("123.0", "0x7b.0#7", 10, "0.12", "0x0.1ec#7"); test("123.0", "0x7b.0#7", 100, "9.7e-29", "0x7.bE-24#7"); test("-123.0", "-0x7b.0#7", 0, "-123.0", "-0x7b.0#7"); test("-123.0", "-0x7b.0#7", 1, "-61.5", "-0x3d.8#7"); test("-123.0", "-0x7b.0#7", 10, "-0.12", "-0x0.1ec#7"); test("-123.0", "-0x7b.0#7", 100, "-9.7e-29", "-0x7.bE-24#7"); test( "3.1415926535897931", "0x3.243f6a8885a30#53", 0, "3.1415926535897931", "0x3.243f6a8885a30#53", ); test( "3.1415926535897931", "0x3.243f6a8885a30#53", 1, "1.5707963267948966", "0x1.921fb54442d18#53", ); test( "3.1415926535897931", "0x3.243f6a8885a30#53", 10, "0.0030679615757712823", "0x0.00c90fdaa22168c0#53", ); test( "3.1415926535897931", "0x3.243f6a8885a30#53", 100, "2.4782796245465248e-30", "0x3.243f6a8885a30E-25#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", 0, "-3.1415926535897931", "-0x3.243f6a8885a30#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", 1, "-1.5707963267948966", "-0x1.921fb54442d18#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", 10, "-0.0030679615757712823", "-0x0.00c90fdaa22168c0#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", 100, "-2.4782796245465248e-30", "-0x3.243f6a8885a30E-25#53", ); } #[test] fn test_shr_unsigned() { test_shr_unsigned_helper::(|_, _, _| {}); test_shr_unsigned_helper::(|_, _, _| {}); test_shr_unsigned_helper::(|x, v, shifted| { let mut n = rug::Float::exact_from(&x); n >>= v; assert_eq!( ComparableFloatRef(&Float::from(&n)), ComparableFloatRef(&shifted) ); let n = rug::Float::exact_from(&x) >> v; assert_eq!( ComparableFloatRef(&Float::from(&n)), ComparableFloatRef(&shifted) ); }); test_shr_unsigned_helper::(|_, _, _| {}); test_shr_unsigned_helper::(|_, _, _| {}); test_shr_unsigned_helper::(|_, _, _| {}); } fn test_shr_signed_helper(f: F) where Float: ShrAssign + Shr, for<'a> &'a Float: Shr, { let test = |s, s_hex, v: i8, out: &str, out_hex: &str| { let x = parse_hex_string(s_hex); assert_eq!(x.to_string(), s); let v = T::from(v); let mut n = x.clone(); n >>= v; assert_eq!(n.to_string(), out); assert_eq!(to_hex_string(&n), out_hex); assert!(n.is_valid()); let n = x.clone() >> v; assert_eq!(n.to_string(), out); assert!(n.is_valid()); let n = &x >> v; assert_eq!(n.to_string(), out); assert!(n.is_valid()); f(x, v, n); }; test("NaN", "NaN", 0, "NaN", "NaN"); test("NaN", "NaN", 10, "NaN", "NaN"); test("NaN", "NaN", -10, "NaN", "NaN"); test("Infinity", "Infinity", 0, "Infinity", "Infinity"); test("Infinity", "Infinity", 10, "Infinity", "Infinity"); test("Infinity", "Infinity", -10, "Infinity", "Infinity"); test("-Infinity", "-Infinity", 0, "-Infinity", "-Infinity"); test("-Infinity", "-Infinity", 10, "-Infinity", "-Infinity"); test("-Infinity", "-Infinity", -10, "-Infinity", "-Infinity"); test("0.0", "0x0.0", 10, "0.0", "0x0.0"); test("0.0", "0x0.0", -10, "0.0", "0x0.0"); test("-0.0", "-0x0.0", 10, "-0.0", "-0x0.0"); test("-0.0", "-0x0.0", -10, "-0.0", "-0x0.0"); test("123.0", "0x7b.0#7", 0, "123.0", "0x7b.0#7"); test("123.0", "0x7b.0#7", 1, "61.5", "0x3d.8#7"); test("123.0", "0x7b.0#7", 10, "0.12", "0x0.1ec#7"); test("123.0", "0x7b.0#7", 100, "9.7e-29", "0x7.bE-24#7"); test("123.0", "0x7b.0#7", -1, "246.0", "0xf6.0#7"); test("123.0", "0x7b.0#7", -10, "1.26e5", "0x1.ecE+4#7"); test("123.0", "0x7b.0#7", -100, "1.56e32", "0x7.bE+26#7"); test("-123.0", "-0x7b.0#7", 0, "-123.0", "-0x7b.0#7"); test("-123.0", "-0x7b.0#7", 1, "-61.5", "-0x3d.8#7"); test("-123.0", "-0x7b.0#7", 10, "-0.12", "-0x0.1ec#7"); test("-123.0", "-0x7b.0#7", 100, "-9.7e-29", "-0x7.bE-24#7"); test("-123.0", "-0x7b.0#7", -1, "-246.0", "-0xf6.0#7"); test("-123.0", "-0x7b.0#7", -10, "-1.26e5", "-0x1.ecE+4#7"); test("-123.0", "-0x7b.0#7", -100, "-1.56e32", "-0x7.bE+26#7"); test( "3.1415926535897931", "0x3.243f6a8885a30#53", 0, "3.1415926535897931", "0x3.243f6a8885a30#53", ); test( "3.1415926535897931", "0x3.243f6a8885a30#53", 1, "1.5707963267948966", "0x1.921fb54442d18#53", ); test( "3.1415926535897931", "0x3.243f6a8885a30#53", 10, "0.0030679615757712823", "0x0.00c90fdaa22168c0#53", ); test( "3.1415926535897931", "0x3.243f6a8885a30#53", 100, "2.4782796245465248e-30", "0x3.243f6a8885a30E-25#53", ); test( "3.1415926535897931", "0x3.243f6a8885a30#53", -1, "6.283185307179586", "0x6.487ed5110b460#53", ); test( "3.1415926535897931", "0x3.243f6a8885a30#53", -10, "3216.9908772759482", "0xc90.fdaa22168c0#53", ); test( "3.1415926535897931", "0x3.243f6a8885a30#53", -100, "3.9824418129956972e30", "0x3.243f6a8885a30E+25#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", 0, "-3.1415926535897931", "-0x3.243f6a8885a30#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", 1, "-1.5707963267948966", "-0x1.921fb54442d18#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", 10, "-0.0030679615757712823", "-0x0.00c90fdaa22168c0#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", 100, "-2.4782796245465248e-30", "-0x3.243f6a8885a30E-25#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", -1, "-6.283185307179586", "-0x6.487ed5110b460#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", -10, "-3216.9908772759482", "-0xc90.fdaa22168c0#53", ); test( "-3.1415926535897931", "-0x3.243f6a8885a30#53", -100, "-3.9824418129956972e30", "-0x3.243f6a8885a30E+25#53", ); } #[test] fn test_shr_signed() { test_shr_signed_helper::(|_, _, _| {}); test_shr_signed_helper::(|_, _, _| {}); test_shr_signed_helper::(|x, v, shifted| { let mut n = rug::Float::exact_from(&x); n >>= v; assert_eq!( ComparableFloatRef(&Float::from(&n)), ComparableFloatRef(&shifted) ); let n = rug::Float::exact_from(&x) >> v; assert_eq!( ComparableFloatRef(&Float::from(&n)), ComparableFloatRef(&shifted) ); }); test_shr_signed_helper::(|_, _, _| {}); test_shr_signed_helper::(|_, _, _| {}); test_shr_signed_helper::(|_, _, _| {}); } fn shr_properties_helper_unsigned() where for<'a> &'a Integer: Shr, Float: Shl + Shr + ShrAssign, for<'a> &'a Float: Shr, i64: TryFrom, u64: TryFrom, { float_unsigned_pair_gen_var_2::().test_properties(|(n, u)| { let mut mut_n = n.clone(); mut_n >>= u; assert!(mut_n.is_valid()); let shifted = mut_n; let shifted_alt = &n >> u; assert!(shifted_alt.is_valid()); assert_eq!( ComparableFloatRef(&shifted_alt), ComparableFloatRef(&shifted) ); let shifted_alt = n.clone() >> u; assert!(shifted_alt.is_valid()); assert_eq!( ComparableFloatRef(&shifted_alt), ComparableFloatRef(&shifted) ); assert_eq!(n.get_prec(), shifted.get_prec()); if !n.is_nan() { assert!((&n >> u).le_abs(&n)); } assert_eq!(ComparableFloat(-&n >> u), ComparableFloat(-(&n >> u))); assert_eq!(ComparableFloatRef(&(&n >> u << u)), ComparableFloatRef(&n)); assert_eq!( ComparableFloat(&n >> u), ComparableFloat(&n * Float::power_of_2(i64::exact_from(u).checked_neg().unwrap())) ); assert_eq!( ComparableFloat(&n >> u), ComparableFloat(n / Float::power_of_2(u64::exact_from(u))) ); }); float_gen().test_properties(|n| { assert_eq!(ComparableFloat(&n >> T::ZERO), ComparableFloat(n)); }); unsigned_gen::().test_properties(|u| { assert!((Float::NAN >> u).is_nan()); assert_eq!(Float::INFINITY >> u, Float::INFINITY); assert_eq!(Float::NEGATIVE_INFINITY >> u, Float::NEGATIVE_INFINITY); assert_eq!( ComparableFloat(Float::ZERO >> u), ComparableFloat(Float::ZERO) ); assert_eq!( ComparableFloat(Float::NEGATIVE_ZERO >> u), ComparableFloat(Float::NEGATIVE_ZERO) ); }); unsigned_gen_var_5::().test_properties(|u| { assert!((Float::ONE >> u).is_power_of_2()); }); } fn shr_properties_helper_signed() where for<'a> &'a Integer: Shr, Float: Shl + ShrAssign + Shr, for<'a> &'a Float: Shl + Shr + Shr<::Output, Output = Float>, i64: TryFrom, { float_signed_pair_gen_var_2::().test_properties(|(n, i)| { let mut mut_n = n.clone(); mut_n >>= i; assert!(mut_n.is_valid()); let shifted = mut_n; let shifted_alt = &n >> i; assert!(shifted_alt.is_valid()); assert_eq!( ComparableFloatRef(&shifted_alt), ComparableFloatRef(&shifted) ); let shifted_alt = n.clone() >> i; assert!(shifted_alt.is_valid()); assert_eq!( ComparableFloatRef(&shifted_alt), ComparableFloatRef(&shifted) ); assert_eq!(n.get_prec(), shifted.get_prec()); if i >= T::ZERO { assert_eq!( ComparableFloat(&n >> i.unsigned_abs()), ComparableFloat(shifted) ); } assert_eq!(ComparableFloat(-&n >> i), ComparableFloat(-(&n >> i))); if let Some(neg_i) = i.checked_neg() { assert_eq!(ComparableFloat(&n >> neg_i), ComparableFloat(&n << i)); } assert_eq!(ComparableFloatRef(&(&n >> i << i)), ComparableFloatRef(&n)); assert_eq!( ComparableFloat(&n >> i), ComparableFloat(&n * Float::power_of_2(i64::exact_from(i).checked_neg().unwrap())) ); assert_eq!( ComparableFloat(&n >> i), ComparableFloat(n / Float::power_of_2(i64::exact_from(i))) ); }); float_gen().test_properties(|n| { assert_eq!(ComparableFloat(&n >> T::ZERO), ComparableFloat(n)); }); signed_gen::().test_properties(|i| { assert!((Float::NAN >> i).is_nan()); assert_eq!(Float::INFINITY >> i, Float::INFINITY); assert_eq!(Float::NEGATIVE_INFINITY >> i, Float::NEGATIVE_INFINITY); assert_eq!( ComparableFloat(Float::ZERO >> i), ComparableFloat(Float::ZERO) ); assert_eq!( ComparableFloat(Float::NEGATIVE_ZERO >> i), ComparableFloat(Float::NEGATIVE_ZERO) ); }); signed_gen_var_5::().test_properties(|i| { assert!((Float::ONE >> i).is_power_of_2()); }); } #[test] fn shr_properties() { apply_fn_to_unsigneds!(shr_properties_helper_unsigned); apply_fn_to_signeds!(shr_properties_helper_signed); float_unsigned_pair_gen_var_2::().test_properties(|(n, u)| { let shifted = &n >> u; let mut rug_n = rug::Float::exact_from(&n); rug_n >>= u; assert_eq!( ComparableFloatRef(&Float::from(&rug_n)), ComparableFloatRef(&shifted) ); assert_eq!( ComparableFloat(Float::from(&(rug::Float::exact_from(&n) >> u))), ComparableFloat(shifted) ); }); float_signed_pair_gen_var_2::().test_properties(|(n, i)| { let shifted = &n >> i; let mut rug_n = rug::Float::exact_from(&n); rug_n >>= i; assert_eq!( ComparableFloatRef(&Float::from(&rug_n)), ComparableFloatRef(&shifted) ); assert_eq!( ComparableFloat(Float::from(&(rug::Float::exact_from(&n) >> i))), ComparableFloat(shifted) ); }); }