#![allow(dead_code)]
const TWO_COMPLEMENT_64: u64 = 0x8000_0000_0000_0000_u64;
const TWO_COMPLEMENT_CI_64: i64 = TWO_COMPLEMENT_64 as i64;
#[inline]
#[must_use]
pub fn almost_equal_as_int(a: f64, b: f64, ulps: u64) -> bool {
debug_assert!(a.is_finite());
debug_assert!(b.is_finite());
let mut a_i: i64 = a.to_bits() as i64;
let mut b_i: i64 = b.to_bits() as i64;
if a_i < 0i64 {
a_i = TWO_COMPLEMENT_CI_64 - a_i;
}
if b_i < 0i64 {
b_i = TWO_COMPLEMENT_CI_64 - b_i;
}
let diff = (a_i as i128) - (b_i as i128);
diff.abs() <= ulps as i128
}
#[must_use]
pub fn close_enough(a: f64, b: f64, eps: f64) -> bool {
if !a.is_finite() || !b.is_finite() || !eps.is_finite() || eps < 0.0 {
return false;
}
(a - b).abs() <= eps
}
#[must_use]
pub fn perturbed_ulps_as_int(f: f64, c: i64) -> f64 {
if f == 0.0 && c == -1 {
return -0.0;
}
let mut f_i: i64 = f.to_bits() as i64;
f_i += c;
f64::from_bits(f_i as u64)
}
#[cfg(test)]
mod test_almost_equal_as_int {
use super::*;
#[test]
fn test_almost_equal_as_int_negative_zero() {
assert!(almost_equal_as_int(0.0, -0.0, 0));
}
#[test]
fn test_almost_equal_as_int_nearby_numbers() {
let result: bool = almost_equal_as_int(2.0, 1.999999999999999, 10);
assert_eq!(result, true);
let result: bool = almost_equal_as_int(-2.0, -1.999999999999999, 10);
assert_eq!(result, true);
}
#[test]
fn test_almost_equal_as_int_slightly_more_distant() {
let result: bool = almost_equal_as_int(2.0, 1.999999999999998, 10);
assert_eq!(result, true);
let result: bool = almost_equal_as_int(-2.0, -1.999999999999998, 10);
assert_eq!(result, true);
}
#[test]
fn test_almost_equal_as_int_slightly_more_distant_reversed() {
let result: bool = almost_equal_as_int(1.999999999999998, 2.0, 10);
assert_eq!(result, true);
let result: bool = almost_equal_as_int(-1.999999999999998, -2.0, 10);
assert_eq!(result, true);
}
#[test]
fn test_almost_equal_as_int_distant() {
let result: bool = almost_equal_as_int(2.0, 1.999999999999997, 10);
assert_eq!(result, false);
let result: bool = almost_equal_as_int(-2.0, -1.999999999999997, 10);
assert_eq!(result, false);
}
#[test]
fn test_almost_equal_as_int_distant_reversed() {
let result: bool = almost_equal_as_int(1.999999999999997, 2.0, 10);
assert_eq!(result, false);
let result: bool = almost_equal_as_int(-1.999999999999997, -2.0, 10);
assert_eq!(result, false);
}
#[test]
fn test_almost_equal_as_int_upper_limit_small() {
let mut f_u: u64 = f64::MAX.to_bits();
f_u -= 2;
let f_f = f64::from_bits(f_u);
let result: bool = almost_equal_as_int(f64::MAX, f_f, 3);
assert_eq!(result, true);
}
#[test]
fn test_almost_equal_as_int_upper_limit_large() {
let mut f_u: u64 = f64::MAX.to_bits();
f_u -= 4;
let f_f = f64::from_bits(f_u);
let result: bool = almost_equal_as_int(f64::MAX, f_f, 3);
assert_eq!(result, false);
}
#[test]
fn test_almost_equal_as_int_lower_limit_small() {
let mut f_u: u64 = f64::MIN.to_bits();
f_u -= 2;
let f_f = f64::from_bits(f_u);
let result: bool = almost_equal_as_int(f64::MIN, f_f, 3);
assert_eq!(result, true);
}
#[test]
fn test_almost_equal_as_int_lower_limit_large() {
let mut f_u: u64 = f64::MIN.to_bits();
f_u -= 4;
let f_f = f64::from_bits(f_u);
let result: bool = almost_equal_as_int(f64::MIN, f_f, 3);
assert_eq!(result, false);
}
#[test]
fn test_almost_equal_as_int_some_numbers() {
let result: bool = almost_equal_as_int(100.0, -300.0, 10);
assert_eq!(result, false);
}
#[test]
#[ignore = "printing"]
fn test_print() {
print_numbers();
assert!(true);
}
fn print_number(f: f64, o: i64) {
let mut f_i: i64 = f.to_bits() as i64;
f_i += o;
println!("{:.20} Ox{:X} {:.}", f, f_i, f_i);
}
pub fn print_numbers() {
let f: f64 = 2.0f64;
print_number(f, 0);
println!("");
let f: f64 = 1.999999999999998;
for i in -10..=10i64 {
print_number(f, i);
}
println!("");
let f: f64 = 0.0;
print_number(f, 0 as i64);
let o: i64 = i64::from_ne_bytes(0x8000_0000_0000_0000u64.to_ne_bytes());
print_number(f, o);
println!("");
for i in 0..=3i64 {
print_number(f, i);
}
println!("");
let c_i: i64 = i64::from_ne_bytes(0x8000_0000_0000_0000u64.to_ne_bytes());
for i in 0..=3i64 {
print_number(f, i + c_i);
}
println!("");
}
#[test]
fn test_perturbed_ulps_as_int_0_minus_1() {
let result = perturbed_ulps_as_int(0.0, -1);
assert_eq!(result, -0.0);
assert!(almost_equal_as_int(result, 0.0, 0));
assert_eq!(result.to_bits(), (-0.0f64).to_bits());
}
#[test]
fn test_perturbed_ulps_as_int() {
let t = 1.0;
let tt = perturbed_ulps_as_int(t, -1);
let res = almost_equal_as_int(t, tt, 1);
assert_eq!(res, true);
let t = 1.0;
let tt = perturbed_ulps_as_int(t, -1000);
let res = almost_equal_as_int(t, tt, 1000);
assert_eq!(res, true);
let t = f64::MAX;
let tt = perturbed_ulps_as_int(t, -1000);
let res = almost_equal_as_int(t, tt, 1000);
assert_eq!(res, true);
let t = f64::MAX;
let tt = perturbed_ulps_as_int(t, -1000000000);
let res = almost_equal_as_int(t, tt, 1000000000);
assert_eq!(res, true);
}
#[test]
fn test_positive_negative_zero() {
assert!(almost_equal_as_int(-0f64, 0f64, 0));
}
}
#[inline]
pub fn diff_of_prod(a: f64, b: f64, c: f64, d: f64) -> f64 {
let cd = c * d;
let err = (-c).mul_add(d, cd);
let dop = a.mul_add(b, -cd);
dop + err
}
#[inline]
pub fn sum_of_prod(a: f64, b: f64, c: f64, d: f64) -> f64 {
let cd = c * d;
let err = c.mul_add(d, -cd);
let sop = a.mul_add(b, cd);
sop + err
}
#[inline]
pub fn min_5(a: f64, b: f64, c: f64, d: f64, e: f64) -> f64 {
a.min(b).min(c).min(d).min(e)
}
#[inline]
pub fn min_4(a: f64, b: f64, c: f64, d: f64) -> f64 {
a.min(b).min(c).min(d)
}
#[inline]
pub fn min_3(a: f64, b: f64, c: f64) -> f64 {
a.min(b).min(c)
}
#[cfg(test)]
mod test_diff_of_prod {
use crate::point::point;
use super::*;
const _0: f64 = 0f64;
const _1: f64 = 0f64;
const _2: f64 = 0f64;
#[test]
fn test_diff_of_prod0() {
let p0 = point(10000.0, 10000.0);
let p1 = point(-10001.0, -10000.0);
let res0 = p0.perp(p1);
let res1 = diff_of_prod(p0.x, p1.y, p0.y, p1.x);
assert_eq!(res0, res1);
}
#[test]
fn test_diff_of_prod1() {
let p0 = point(100000.0, 100000.0);
let p1 = point(-100001.0, -100000.0);
let res0 = p0.perp(p1);
let res1 = diff_of_prod(p0.x, p1.y, p0.y, p1.x);
assert_eq!(res0, res1);
}
}
#[cfg(test)]
mod test_sum_min_close {
use super::*;
#[test]
fn test_sum_of_prod_basic() {
let v = sum_of_prod(0.5, 2.0, 0.25, 4.0);
assert_eq!(v, 2.0);
let v2 = sum_of_prod(3.0, -2.0, 4.0, 0.5);
assert_eq!(v2, -6.0 + 2.0);
}
#[test]
fn test_min_3_4_5() {
assert_eq!(min_3(3.0, 2.0, 1.0), 1.0);
assert_eq!(min_3(-1.0, -2.0, 0.0), -2.0);
assert_eq!(min_4(4.0, 3.0, 2.0, 1.0), 1.0);
assert_eq!(min_4(-1.0, -2.0, -3.0, 0.0), -3.0);
assert_eq!(min_5(5.0, 4.0, 3.0, 2.0, 1.0), 1.0);
assert_eq!(min_5(-1.0, -2.0, -3.0, -4.0, 0.0), -4.0);
}
#[test]
fn test_close_enough_bounds() {
assert!(close_enough(1.0, 1.0009, 0.001));
assert!(!close_enough(1.0, 1.002, 0.001));
assert!(close_enough(-1.0, -1.0005, 0.001));
}
}