#![allow(clippy::approx_constant)]
use inari::*;
fn log2_point_reduced(x: f64) -> Interval {
let x = interval!(x, x).unwrap();
assert!(x.subset(const_interval!(0.8284271247461901, 1.17157287525381)));
const N: usize = 22;
const C: [Interval; N] = [
const_interval!(0.0, 0.0),
const_interval!(1.4426950408889634, 1.4426950408889636),
const_interval!(-0.7213475204444818, -0.7213475204444817),
const_interval!(0.4808983469629878, 0.48089834696298783),
const_interval!(-0.3606737602222409, -0.36067376022224085),
const_interval!(0.28853900817779266, 0.2885390081777927),
const_interval!(-0.24044917348149392, -0.2404491734814939),
const_interval!(0.2060992915555662, 0.20609929155556622),
const_interval!(-0.18033688011112045, -0.18033688011112042),
const_interval!(0.16029944898766257, 0.1602994489876626),
const_interval!(-0.14426950408889636, -0.14426950408889633),
const_interval!(0.1311540946262694, 0.13115409462626942),
const_interval!(-0.12022458674074696, -0.12022458674074694),
const_interval!(0.11097654160684334, 0.11097654160684335),
const_interval!(-0.10304964577778311, -0.1030496457777831),
const_interval!(9.617966939259755e-2, 9.617966939259756e-2),
const_interval!(-9.016844005556023e-2, -9.016844005556021e-2),
const_interval!(8.486441416993902e-2, 8.486441416993903e-2),
const_interval!(-8.01497244938313e-2, -8.014972449383129e-2),
const_interval!(7.593131794152438e-2, 7.59313179415244e-2),
const_interval!(-7.213475204444818e-2, -7.213475204444816e-2),
const_interval!(6.869976385185539e-2, 6.86997638518554e-2),
];
let xm1 = x - const_interval!(1.0, 1.0);
let mut y = const_interval!(-4.122465510826449, -2.0129226127082265e-3);
for n in (0..N).rev() {
y = y.mul_add(xm1, C[n]);
}
y
}
enum Round {
Down,
Up,
}
fn log2_point(x: f64, rnd: Round) -> Interval {
assert!(x > 0.0 && x < f64::INFINITY);
let (mut b, a) = libm::frexp(x);
let mut a = a as f64;
const BL_RD: f64 = 0.8284271247461901; const BL2_RD: f64 = 0.5857864376269049; if b < BL2_RD {
a -= 1.0;
b *= 2.0;
} else if b < BL_RD {
a -= 0.5;
b = {
let b = Interval::SQRT_2 * interval!(b, b).unwrap();
match rnd {
Round::Down => b.inf(),
Round::Up => b.sup(),
}
};
}
let a = interval!(a, a).unwrap();
a + log2_point_reduced(b)
}
fn log2(x: Interval) -> Interval {
if x.is_empty() {
return x;
}
let inf = if x.inf() <= 0.0 {
f64::NEG_INFINITY
} else {
log2_point(x.inf(), Round::Down).inf()
};
let sup = if x.sup() == f64::INFINITY {
f64::INFINITY
} else {
log2_point(x.sup(), Round::Up).sup()
};
interval!(inf, sup).unwrap()
}
fn ln(x: Interval) -> Interval {
Interval::LN_2 * log2(x)
}
fn log10(x: Interval) -> Interval {
Interval::LOG10_2 * log2(x)
}
fn main() {
let x = interval!("[1.234567]").unwrap();
println!("log2(x) ⊆ {:.15e}", log2(x));
println!("log2(x) ⊆ {:.15e} (MPFR)", x.log2());
assert!(x.log2().subset(log2(x)));
println!("ln(x) ⊆ {:.15e}", ln(x));
println!("ln(x) ⊆ {:.15e} (MPFR)", x.ln());
assert!(x.ln().subset(ln(x)));
println!("log10(x) ⊆ {:.15e}", log10(x));
println!("log10(x) ⊆ {:.15e} (MPFR)", x.log10());
assert!(x.log10().subset(log10(x)));
}