#![cfg(feature = "backend-f64")]
use crate::backend::{NiBackend, NiFloat};
#[derive(Clone, Copy)]
pub struct F64Float(pub f64);
impl NiFloat for F64Float {
#[inline]
fn to_f64(&self) -> f64 {
self.0
}
fn to_decimal_string(&self, digits: u32) -> String {
format!("{:.prec$}", self.0, prec = digits as usize)
}
#[inline]
fn abs(&self) -> Self {
F64Float(self.0.abs())
}
#[inline]
fn lt(&self, other: &Self) -> bool {
self.0 < other.0
}
#[inline]
fn add_assign(&mut self, other: &Self) {
self.0 += other.0;
}
}
pub struct F64Backend;
impl NiBackend for F64Backend {
type Float = F64Float;
#[inline]
fn pi(_precision_bits: u32) -> F64Float {
F64Float(std::f64::consts::PI)
}
#[inline]
fn mul(a: &F64Float, b: &F64Float, _precision_bits: u32) -> F64Float {
F64Float(a.0 * b.0)
}
#[inline]
fn div(num: &F64Float, den: &F64Float, _precision_bits: u32) -> F64Float {
F64Float(num.0 / den.0)
}
#[inline]
fn from_u64(value: u64, _precision_bits: u32) -> F64Float {
F64Float(value as f64)
}
#[inline]
fn two_pow(exp: u32, _precision_bits: u32) -> F64Float {
F64Float(2.0_f64.powi(exp as i32))
}
#[inline]
fn zero(_precision_bits: u32) -> F64Float {
F64Float(0.0)
}
fn epsilon(_precision_bits: u32) -> F64Float {
F64Float(f64::EPSILON)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::compute;
use crate::constants::NI_F64;
use crate::backend::NiFloat;
#[test]
fn f64_backend_matches_constant() {
let val = compute::compute::<F64Backend>(64); let diff = (val.to_f64() - NI_F64).abs();
assert!(diff < 1e-13, "f64 backend drift: {:.2e}", diff);
}
#[test]
fn f64_string_prefix() {
let val = compute::compute::<F64Backend>(64);
let s = val.to_decimal_string(10);
assert!(s.starts_with("1.8893766604"), "got: {}", s);
}
}