#![allow(dead_code)]
use malachite_q::Rational;
use the_q::{Dir, MAX_MAG, Rat};
pub fn rat(q: Rat) -> Rational {
Rational::from_signeds(q.numerator() as i128, q.denominator() as i128)
}
pub fn rat_of(n: i128, d: i128) -> Rational {
Rational::from_signeds(n, d)
}
pub fn zero() -> Rational {
Rational::from_signeds(0i128, 1i128)
}
pub fn one() -> Rational {
Rational::from_signeds(1i128, 1i128)
}
pub fn rabs(x: Rational) -> Rational {
if x < zero() { -x } else { x }
}
pub fn two_pow_b() -> Rational {
Rational::from_signeds(1i128 << 61, 1i128)
}
pub fn max_mag_rat() -> Rational {
Rational::from_signeds(MAX_MAG as i128, 1i128)
}
pub fn fits_budget(r: &Rational) -> bool {
let (n, d) = r.to_numerator_and_denominator();
let max = malachite_nz::natural::Natural::from(MAX_MAG as u64);
n <= max && d <= max
}
pub fn magnitude_fits(r: &Rational) -> bool {
rabs(r.clone()) <= max_mag_rat()
}
pub fn assert_r3(result: Rat, exact: &Rational, what: &str) {
let got = rat(result);
let err = rabs(got.clone() - exact.clone());
let bound = if rabs(exact.clone()) > one() {
rabs(exact.clone())
} else {
one()
};
assert!(
err * two_pow_b() <= bound,
"R3 violated for {what}: got {got}, exact {exact}"
);
}
pub fn assert_exact_if_representable(result: Rat, exact: &Rational, what: &str) {
if fits_budget(exact) {
assert_eq!(
rat(result),
*exact,
"R1 violated for {what}: exact value {exact} is representable but got {}",
rat(result)
);
}
}
pub fn assert_r2(down: Rat, up: Rat, exact: &Rational, what: &str) {
assert!(
rat(down) <= *exact,
"R2 (Down) violated for {what}: {} > {exact}",
rat(down)
);
assert!(
rat(up) >= *exact,
"R2 (Up) violated for {what}: {} < {exact}",
rat(up)
);
}
pub fn assert_wf(q: Rat, what: &str) {
let (n, d) = (q.numerator(), q.denominator());
assert!(d > 0, "I1 violated ({what}): den {d} <= 0");
assert!(d <= MAX_MAG, "I2 violated ({what}): den {d} > MAX_MAG");
assert!(
n.unsigned_abs() <= MAX_MAG as u64,
"I2 violated ({what}): |num| {n} > MAX_MAG"
);
if n == 0 {
assert_eq!(d, 1, "I1 violated ({what}): zero with den {d}");
}
assert_eq!(
gcd_u64(n.unsigned_abs(), d as u64),
1,
"I1 violated ({what}): {n}/{d} is not in lowest terms"
);
}
pub fn gcd_u64(a: u64, b: u64) -> u64 {
let (mut x, mut y) = (a, b);
while y != 0 {
let t = x % y;
x = y;
y = t;
}
x
}
pub struct Rng(u64);
impl Rng {
pub fn new(seed: u64) -> Rng {
Rng(seed | 1)
}
pub fn next_u64(&mut self) -> u64 {
let mut x = self.0;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
self.0 = x;
x.wrapping_mul(0x2545_F491_4F6C_DD1D)
}
pub fn below(&mut self, n: u64) -> u64 {
self.next_u64() % n
}
pub fn q(&mut self) -> Rat {
loop {
let class = self.below(6);
let (n, d): (i64, i64) = match class {
0 => (self.below(21) as i64 - 10, self.below(10) as i64 + 1),
1 => (self.below(10001) as i64 - 5000, 10000),
2 => (
self.below(1 << 20) as i64 - (1 << 19),
self.below(1 << 20) as i64 + 1,
),
3 => (
self.below(1 << 40) as i64 - (1 << 39),
self.below(1 << 40) as i64 + 1,
),
4 => (
(self.next_u64() % (MAX_MAG as u64)) as i64,
(self.next_u64() % (MAX_MAG as u64)) as i64 + 1,
),
_ => (
MAX_MAG - self.below(4) as i64,
MAX_MAG - self.below(4) as i64,
),
};
if let Some(q) = Rat::new(n, d) {
return q;
}
}
}
pub fn q_nonzero(&mut self) -> Rat {
loop {
let q = self.q();
if !q.is_zero() {
return q;
}
}
}
pub fn q_unit(&mut self) -> Rat {
loop {
let d = self.below(1 << 30) as i64 + 1;
let n = self.below(d as u64 + 1) as i64;
if let Some(q) = Rat::new(n, d) {
return q;
}
}
}
}
pub const DIRS: [Dir; 3] = [Dir::Down, Dir::Up, Dir::Nearest];