// 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 malachite_nz::test_util::generators::integer_unsigned_pair_gen_var_2;
use std::ops::{Shl, ShlAssign, Shr};
fn test_shl_unsigned_helper(f: F)
where
Float: ShlAssign + Shl,
for<'a> &'a Float: Shl,
{
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, "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, "-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,
"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,
"-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_shl_unsigned() {
test_shl_unsigned_helper::(|_, _, _| {});
test_shl_unsigned_helper::(|_, _, _| {});
test_shl_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_shl_unsigned_helper::(|_, _, _| {});
test_shl_unsigned_helper::(|_, _, _| {});
test_shl_unsigned_helper::(|_, _, _| {});
}
fn test_shl_signed_helper(f: F)
where
Float: ShlAssign + Shl,
for<'a> &'a Float: Shl,
{
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, "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", -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, "-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", -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,
"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",
-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,
"-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",
-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_shl_signed() {
test_shl_signed_helper::(|_, _, _| {});
test_shl_signed_helper::(|_, _, _| {});
test_shl_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_shl_signed_helper::(|_, _, _| {});
test_shl_signed_helper::(|_, _, _| {});
test_shl_signed_helper::(|_, _, _| {});
}
fn shl_properties_helper_unsigned()
where
for<'a> &'a Integer: Shl,
Float: Shl + ShlAssign + Shr,
for<'a> &'a Float: Shl,
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).ge_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(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());
});
integer_unsigned_pair_gen_var_2::().test_properties(|(n, u)| {
assert_eq!(&n << u, Float::from(n) << u);
});
}
fn shl_properties_helper_signed()
where
for<'a> &'a Integer: Shl,
Float: Shl + ShlAssign + Shr,
for<'a> &'a Float: Shl
+ Shl<::Output, Output = Float>
+ Shr,
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)))
);
});
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 shl_properties() {
apply_fn_to_unsigneds!(shl_properties_helper_unsigned);
apply_fn_to_signeds!(shl_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)
);
});
}