extern crate amplify_apfloat;
extern crate amplify_num;
use std::cmp::Ordering;
use amplify_apfloat::ppc::DoubleDouble;
use amplify_apfloat::{Category, Float, Round};
use amplify_num::u256;
#[test]
fn ppc_double_double() {
let test = DoubleDouble::ZERO;
let expected = "0x0p+0".parse::<DoubleDouble>().unwrap();
assert!(test.is_zero());
assert!(!test.is_negative());
assert!(test.bitwise_eq(expected));
assert_eq!(u256::ZERO, test.to_bits());
let test = -DoubleDouble::ZERO;
let expected = "-0x0p+0".parse::<DoubleDouble>().unwrap();
assert!(test.is_zero());
assert!(test.is_negative());
assert!(test.bitwise_eq(expected));
assert_eq!(u256::from(0x8000000000000000u128), test.to_bits());
let test = "1.0".parse::<DoubleDouble>().unwrap();
assert_eq!(u256::from(0x3ff0000000000000u128), test.to_bits());
let test = "1.79769313486231580793728971405301e+308"
.parse::<DoubleDouble>()
.unwrap();
assert_eq!(u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128), test.to_bits());
let test = "2.00416836000897277799610805135016e-292"
.parse::<DoubleDouble>()
.unwrap();
assert_eq!(u256::from(0x0000000000000000_0360000000000000u128), test.to_bits());
}
#[test]
fn ppc_double_double_add_special() {
let data = [
(
u256::from(0x3ff0000000000000u128),
u256::from(0xbff0000000000000u128),
Category::Zero,
Round::NearestTiesToEven,
),
(
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
u256::from(0x7948000000000000u128),
Category::Infinity,
Round::NearestTiesToEven,
),
(
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
u256::from(0x75effffffffffffe_7947ffffffffffffu128),
Category::Normal,
Round::NearestTiesToEven,
),
(
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
Category::Infinity,
Round::NearestTiesToEven,
),
(
u256::from(0x7ff8000000000000u128),
u256::from(0x3ff0000000000000u128),
Category::NaN,
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.add_r(a2, round).value;
assert_eq!(expected, a1.category(), "{:#x} + {:#x}", op1, op2);
}
{
let a1 = DoubleDouble::from_bits(op1);
let mut a2 = DoubleDouble::from_bits(op2);
a2 = a2.add_r(a1, round).value;
assert_eq!(expected, a2.category(), "{:#x} + {:#x}", op2, op1);
}
}
}
#[test]
fn ppc_double_double_add() {
let data = [
(
u256::from(0x3ff0000000000000u128),
u256::from(0x3960000000000000u128),
u256::from(0x3960000000000000_3ff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x3ff0000000000000u128),
u256::from(0x3950000000000000u128),
u256::from(0x3950000000000000_3ff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x3950000000000000_3ff0000000000000u128),
u256::from(0x3950000000000000u128),
u256::from(0x3960000000000000_3ff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x3ff0000000000000u128),
u256::from(0x0000000000000001u128),
u256::from(0x0000000000000001_3ff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0xf950000000000000_7fefffffffffffffu128),
u256::from(0x7c90000000000000u128),
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
Round::NearestTiesToEven,
),
(
u256::from(0x7c90000000000000u128),
u256::from(0xf950000000000000_7fefffffffffffffu128),
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.add_r(a2, round).value;
assert_eq!(expected, a1.to_bits(), "{:#x} + {:#x}", op1, op2);
}
{
let a1 = DoubleDouble::from_bits(op1);
let mut a2 = DoubleDouble::from_bits(op2);
a2 = a2.add_r(a1, round).value;
assert_eq!(expected, a2.to_bits(), "{:#x} + {:#x}", op2, op1);
}
}
}
#[test]
fn ppc_double_double_subtract() {
let data = [
(
u256::from(0x3ff0000000000000u128),
u256::from(0xb960000000000000u128),
u256::from(0x3960000000000000_3ff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x3ff0000000000000u128),
u256::from(0xb950000000000000u128),
u256::from(0x3950000000000000_3ff0000000000000u128),
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.sub_r(a2, round).value;
assert_eq!(expected, a1.to_bits(), "{:#x} - {:#x}", op1, op2);
}
}
#[test]
fn ppc_double_double_multiply_special() {
let data = [
(
u256::from(0x7ff8000000000000u128),
u256::from(0x7ff8000000000000u128),
Category::NaN,
Round::NearestTiesToEven,
),
(u256::from(0x7ff8000000000000u128), u256::ZERO, Category::NaN, Round::NearestTiesToEven),
(
u256::from(0x7ff8000000000000u128),
u256::from(0x7ff0000000000000u128),
Category::NaN,
Round::NearestTiesToEven,
),
(
u256::from(0x7ff8000000000000u128),
u256::from(0x3ff0000000000000u128),
Category::NaN,
Round::NearestTiesToEven,
),
(
u256::from(0x7ff0000000000000u128),
u256::from(0x7ff0000000000000u128),
Category::Infinity,
Round::NearestTiesToEven,
),
(u256::from(0x7ff0000000000000u128), u256::ZERO, Category::NaN, Round::NearestTiesToEven),
(
u256::from(0x7ff0000000000000u128),
u256::from(0x3ff0000000000000u128),
Category::Infinity,
Round::NearestTiesToEven,
),
(u256::ZERO, u256::ZERO, Category::Zero, Round::NearestTiesToEven),
(u256::ZERO, u256::from(0x3ff0000000000000u128), Category::Zero, Round::NearestTiesToEven),
];
for &(op1, op2, expected, round) in &data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.mul_r(a2, round).value;
assert_eq!(expected, a1.category(), "{:#x} * {:#x}", op1, op2);
}
{
let a1 = DoubleDouble::from_bits(op1);
let mut a2 = DoubleDouble::from_bits(op2);
a2 = a2.mul_r(a1, round).value;
assert_eq!(expected, a2.category(), "{:#x} * {:#x}", op2, op1);
}
}
}
#[test]
fn ppc_double_double_multiply() {
let data = [
(
u256::from(0x3c75555555555556_3fd5555555555555u128),
u256::from(0x4008000000000000u128),
u256::from(0x3ff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x0000000000000001_3ff0000000000000u128),
u256::from(0x3ff0000000000000u128),
u256::from(0x0000000000000001_3ff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x0000000000000001_3ff0000000000000u128),
u256::from(0x0000000000000001_3ff0000000000000u128),
u256::from(0x0000000000000002_3ff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x0000000000000001_bff0000000000000u128),
u256::from(0x0000000000000001_3ff0000000000000u128),
u256::from(0xbff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x3fe0000000000000u128),
u256::from(0x0000000000000002_3ff0000000000000u128),
u256::from(0x0000000000000001_3fe0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x3fe0000000000000u128),
u256::from(0x0000000000000001_3ff0000000000000u128),
u256::from(0x3fe0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
u256::from(0x3950000000000000_3ff0000000000000u128),
u256::from(0x7ff0000000000000u128),
Round::NearestTiesToEven,
),
(
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
u256::from(0x3940000000000000_3ff0000000000000u128),
u256::from(0x7c8fffffffffffff_7fefffffffffffffu128),
Round::NearestTiesToEven,
),
(
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
u256::from(0x3930000000000000_3ff0000000000000u128),
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.mul_r(a2, round).value;
assert_eq!(expected, a1.to_bits(), "{:#x} * {:#x}", op1, op2);
}
{
let a1 = DoubleDouble::from_bits(op1);
let mut a2 = DoubleDouble::from_bits(op2);
a2 = a2.mul_r(a1, round).value;
assert_eq!(expected, a2.to_bits(), "{:#x} * {:#x}", op2, op1);
}
}
}
#[test]
fn ppc_double_double_divide() {
let data = [
(
u256::from(0x3ff0000000000000u128),
u256::from(0x4008000000000000u128),
u256::from(0x3c75555555555556_3fd5555555555555u128),
Round::NearestTiesToEven,
),
];
for &(op1, op2, expected, round) in &data {
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.div_r(a2, round).value;
assert_eq!(expected, a1.to_bits(), "{:#x} / {:#x}", op1, op2);
}
}
#[test]
fn ppc_double_double_remainder() {
let data = [
(
u256::from(0x3cb8000000000000_4008000000000000u128),
u256::from(0x3ca4000000000000_3ff4000000000000u128),
u256::from(0x3c90000000000000_3fe0000000000000u128),
),
(
u256::from(0x3cb8000000000000_4008000000000000u128),
u256::from(0x3cac000000000000_3ffc000000000000u128),
u256::from(0xbc90000000000000_bfe0000000000000u128),
),
];
for &(op1, op2, expected) in &data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
let result = a1.ieee_rem(a2).value;
assert_eq!(expected, result.to_bits(), "ieee_rem({:#x}, {:#x})", op1, op2);
}
}
#[test]
fn ppc_double_double_mod() {
let data = [
(
u256::from(0x3cb8000000000000_4008000000000000u128),
u256::from(0x3ca4000000000000_3ff4000000000000u128),
u256::from(0x3c90000000000000_3fe0000000000000u128),
),
(
u256::from(0x3cb8000000000000_4008000000000000u128),
u256::from(0x3cac000000000000_3ffc000000000000u128),
u256::from(0xbc98000000000000_3ff4000000000001u128),
),
];
for &(op1, op2, expected) in &data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
let r = (a1 % a2).value;
assert_eq!(expected, r.to_bits(), "fmod({:#x}, {:#x})", op1, op2);
}
}
#[test]
fn ppc_double_double_fma() {
let mut a = "2".parse::<DoubleDouble>().unwrap();
a = a
.mul_add("3".parse::<DoubleDouble>().unwrap(), "4".parse::<DoubleDouble>().unwrap())
.value;
assert_eq!(Some(Ordering::Equal), "10".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
}
#[test]
fn ppc_double_double_round_to_integral() {
{
let a = "1.5".parse::<DoubleDouble>().unwrap();
let a = a.round_to_integral(Round::NearestTiesToEven).value;
assert_eq!(Some(Ordering::Equal), "2".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
}
{
let a = "2.5".parse::<DoubleDouble>().unwrap();
let a = a.round_to_integral(Round::NearestTiesToEven).value;
assert_eq!(Some(Ordering::Equal), "2".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
}
}
#[test]
fn ppc_double_double_compare() {
let data = [
(
u256::from(0x3ff0000000000000u128),
u256::from(0x3ff0000000000000u128),
Some(Ordering::Equal),
),
(
u256::from(0x3ff0000000000000u128),
u256::from(0x3ff0000000000001u128),
Some(Ordering::Less),
),
(
u256::from(0x3ff0000000000001u128),
u256::from(0x3ff0000000000000u128),
Some(Ordering::Greater),
),
(
u256::from(0x3ff0000000000000u128),
u256::from(0x0000000000000001_3ff0000000000001u128),
Some(Ordering::Less),
),
(u256::from(0x7ff8000000000000u128), u256::from(0x7ff8000000000000u128), None),
(u256::from(0x3ff0000000000000u128), u256::from(0x7ff8000000000000u128), None),
(
u256::from(0x7ff0000000000000u128),
u256::from(0x7ff0000000000000u128),
Some(Ordering::Equal),
),
];
for &(op1, op2, expected) in &data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
assert_eq!(expected, a1.partial_cmp(&a2), "compare({:#x}, {:#x})", op1, op2,);
}
}
#[test]
fn ppc_double_double_bitwise_eq() {
let data = [
(u256::from(0x3ff0000000000000u128), u256::from(0x3ff0000000000000u128), true),
(u256::from(0x3ff0000000000000u128), u256::from(0x3ff0000000000001u128), false),
(u256::from(0x7ff8000000000000u128), u256::from(0x7ff8000000000000u128), true),
(
u256::from(0x7ff8000000000000u128),
u256::from(0x3ff0000000000000_7ff8000000000000u128),
false,
),
(u256::from(0x7ff0000000000000u128), u256::from(0x7ff0000000000000u128), true),
];
for &(op1, op2, expected) in &data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2);
}
}
#[test]
fn ppc_double_double_change_sign() {
let float = DoubleDouble::from_bits(u256::from(0xbcb0000000000000_400f000000000000u128));
{
let actual = float.copy_sign("1".parse::<DoubleDouble>().unwrap());
assert_eq!(u256::from(0xbcb0000000000000_400f000000000000u128), actual.to_bits());
}
{
let actual = float.copy_sign("-1".parse::<DoubleDouble>().unwrap());
assert_eq!(u256::from(0x3cb0000000000000_c00f000000000000u128), actual.to_bits());
}
}
#[test]
fn ppc_double_double_factories() {
assert_eq!(u256::ZERO, DoubleDouble::ZERO.to_bits());
assert_eq!(
u256::from(0x7c8ffffffffffffe_7fefffffffffffffu128),
DoubleDouble::largest().to_bits()
);
assert_eq!(u256::from(0x0000000000000001u128), DoubleDouble::SMALLEST.to_bits());
assert_eq!(u256::from(0x0360000000000000u128), DoubleDouble::smallest_normalized().to_bits());
assert_eq!(
u256::from(0x0000000000000000_8000000000000000u128),
(-DoubleDouble::ZERO).to_bits()
);
assert_eq!(
u256::from(0xfc8ffffffffffffe_ffefffffffffffffu128),
(-DoubleDouble::largest()).to_bits()
);
assert_eq!(
u256::from(0x0000000000000000_8000000000000001u128),
(-DoubleDouble::SMALLEST).to_bits()
);
assert_eq!(
u256::from(0x0000000000000000_8360000000000000u128),
(-DoubleDouble::smallest_normalized()).to_bits()
);
assert!(DoubleDouble::SMALLEST.is_smallest());
assert!(DoubleDouble::largest().is_largest());
}
#[test]
fn ppc_double_double_is_denormal() {
assert!(DoubleDouble::SMALLEST.is_denormal());
assert!(!DoubleDouble::largest().is_denormal());
assert!(!DoubleDouble::smallest_normalized().is_denormal());
{
let data = u256::from(0x4008000000000000_4010000000000000u128);
assert!(DoubleDouble::from_bits(data).is_denormal());
}
}
#[test]
fn ppc_double_double_exact_inverse() {
assert!(
"2.0"
.parse::<DoubleDouble>()
.unwrap()
.get_exact_inverse()
.unwrap()
.bitwise_eq("0.5".parse::<DoubleDouble>().unwrap())
);
}
#[test]
fn ppc_double_double_scalbn() {
let input = u256::from(0x3cb8000000000000_4008000000000000u128);
let result = DoubleDouble::from_bits(input).scalbn(1);
assert_eq!(u256::from(0x3cc8000000000000_4018000000000000u128), result.to_bits());
}
#[test]
fn ppc_double_double_frexp() {
let input = u256::from(0x3cb8000000000000_4008000000000000u128);
let mut exp = 0;
let result = DoubleDouble::from_bits(input).frexp(&mut exp);
assert_eq!(2, exp);
assert_eq!(u256::from(0x3c98000000000000_3fe8000000000000u128), result.to_bits());
}