#![allow(clippy::approx_constant)]
use crate::ported::math::{mnumber, MN_FLOAT, MN_INTEGER};
use std::sync::{Mutex, OnceLock};
use crate::ported::zsh_h::{features, module};
use crate::random_real::random_real;
#[cfg(unix)]
extern "C" {
fn j0(x: f64) -> f64;
fn j1(x: f64) -> f64;
fn jn(n: i32, x: f64) -> f64;
fn y0(x: f64) -> f64;
fn y1(x: f64) -> f64;
fn yn(n: i32, x: f64) -> f64;
fn erf(x: f64) -> f64;
fn erfc(x: f64) -> f64;
fn lgamma(x: f64) -> f64;
fn tgamma(x: f64) -> f64;
fn ilogb(x: f64) -> i32;
fn logb(x: f64) -> f64;
fn nextafter(x: f64, y: f64) -> f64;
fn rint(x: f64) -> f64;
fn scalbn(x: f64, n: i32) -> f64;
fn ldexp(x: f64, exp: i32) -> f64;
fn copysign(x: f64, y: f64) -> f64;
fn expm1(x: f64) -> f64;
fn log1p(x: f64) -> f64;
fn cbrt(x: f64) -> f64;
}
#[allow(unused_variables)]
pub fn math_string(name: &str, arg: &str, id: i32) -> mnumber {
let trimmed = arg.trim_matches(|c: char| c == ' ' || c == '\t'); match id {
MS_RAND48 => {
let _ = trimmed;
mnumber {
l: 0,
d: random_real(),
type_: MN_FLOAT,
}
}
_ => mnumber {
l: 0,
d: 0.0,
type_: MN_INTEGER,
}, }
}
#[allow(unused_variables)]
pub fn setup_(m: *const module) -> i32 {
0
}
pub fn features_(m: *const module, features: &mut Vec<String>) -> i32 {
*features = featuresarray(m, module_features());
0 }
pub fn enables_(m: *const module, enables: &mut Option<Vec<i32>>) -> i32 {
handlefeatures(m, module_features(), enables) }
#[allow(unused_variables)]
pub fn boot_(m: *const module) -> i32 {
0
}
pub fn cleanup_(m: *const module) -> i32 {
setfeatureenables(m, module_features(), None) }
#[allow(unused_variables)]
pub fn finish_(m: *const module) -> i32 {
0
}
pub const MF_ABS: i32 = 0; pub const MF_ACOS: i32 = 1; pub const MF_ACOSH: i32 = 2;
pub const MF_ASIN: i32 = 3;
pub const MF_ASINH: i32 = 4;
pub const MF_ATAN: i32 = 5;
pub const MF_ATANH: i32 = 6;
pub const MF_CBRT: i32 = 7;
pub const MF_CEIL: i32 = 8;
pub const MF_COPYSIGN: i32 = 9;
pub const MF_COS: i32 = 10;
pub const MF_COSH: i32 = 11;
pub const MF_ERF: i32 = 12;
pub const MF_ERFC: i32 = 13;
pub const MF_EXP: i32 = 14;
pub const MF_EXPM1: i32 = 15;
pub const MF_FABS: i32 = 16;
pub const MF_FLOAT: i32 = 17;
pub const MF_FLOOR: i32 = 18;
pub const MF_FMOD: i32 = 19;
pub const MF_GAMMA: i32 = 20;
pub const MF_HYPOT: i32 = 21;
pub const MF_ILOGB: i32 = 22;
pub const MF_INT: i32 = 23;
pub const MF_ISINF: i32 = 24;
pub const MF_ISNAN: i32 = 25;
pub const MF_J0: i32 = 26;
pub const MF_J1: i32 = 27;
pub const MF_JN: i32 = 28;
pub const MF_LDEXP: i32 = 29;
pub const MF_LGAMMA: i32 = 30;
pub const MF_LOG: i32 = 31;
pub const MF_LOG10: i32 = 32;
pub const MF_LOG1P: i32 = 33;
pub const MF_LOG2: i32 = 34;
pub const MF_LOGB: i32 = 35;
pub const MF_NEXTAFTER: i32 = 36;
pub const MF_RINT: i32 = 37;
pub const MF_SCALB: i32 = 38;
pub const MF_SIGNGAM: i32 = 39; pub const MF_SIN: i32 = 40;
pub const MF_SINH: i32 = 41;
pub const MF_SQRT: i32 = 42;
pub const MF_TAN: i32 = 43;
pub const MF_TANH: i32 = 44;
pub const MF_Y0: i32 = 45;
pub const MF_Y1: i32 = 46;
pub const MF_YN: i32 = 47;
pub const MS_RAND48: i32 = 0;
pub const TF_NOCONV: i32 = 1; pub const TF_INT1: i32 = 2; pub const TF_INT2: i32 = 4; pub const TF_NOASS: i32 = 8;
pub const fn tflag(x: i32) -> i32 {
x << 8
}
#[allow(non_snake_case)]
pub fn math_func(_name: &str, argc: i32, argv: &[mnumber], id: i32) -> mnumber {
let mut ret = mnumber {
l: 0,
d: 0.0,
type_: MN_FLOAT,
}; let mut argd: f64 = 0.0; let mut argd2: f64 = 0.0; let mut argi: i32 = 0;
if argc > 0 && (id & tflag(TF_NOCONV)) == 0 {
if (id & tflag(TF_INT1)) != 0 {
argi = if argv[0].type_ == MN_FLOAT {
argv[0].d as i32 } else {
argv[0].l as i32
};
} else {
argd = if argv[0].type_ == MN_INTEGER {
argv[0].l as f64 } else {
argv[0].d
};
}
if argc > 1 {
if (id & tflag(TF_INT2)) != 0 {
argi = if argv[1].type_ == MN_FLOAT {
argv[1].d as i32 } else {
argv[1].l as i32
};
} else {
argd2 = if argv[1].type_ == MN_INTEGER {
argv[1].l as f64 } else {
argv[1].d
};
}
}
}
let mut retd: f64 = 0.0;
match id & 0xff {
MF_ABS => {
ret.type_ = argv[0].type_;
if argv[0].type_ == MN_INTEGER {
ret.l = if argv[0].l < 0 { -argv[0].l } else { argv[0].l };
} else {
ret.d = argv[0].d.abs();
retd = ret.d;
}
}
MF_ACOS => retd = argd.acos(), MF_ACOSH => retd = argd.acosh(), MF_ASIN => retd = argd.asin(), MF_ASINH => retd = argd.asinh(), MF_ATAN => {
retd = if argc == 2 {
argd.atan2(argd2)
} else {
argd.atan()
};
}
MF_ATANH => retd = argd.atanh(), MF_CBRT => retd = unsafe { cbrt(argd) }, MF_CEIL => retd = argd.ceil(), MF_COPYSIGN => retd = unsafe { copysign(argd, argd2) }, MF_COS => retd = argd.cos(), MF_COSH => retd = argd.cosh(), MF_ERF => retd = unsafe { erf(argd) }, MF_ERFC => retd = unsafe { erfc(argd) }, MF_EXP => retd = argd.exp(), MF_EXPM1 => retd = unsafe { expm1(argd) }, MF_FABS => retd = argd.abs(), MF_FLOAT => retd = argd, MF_FLOOR => retd = argd.floor(), MF_FMOD => retd = argd % argd2, MF_GAMMA => retd = unsafe { tgamma(argd) }, MF_HYPOT => retd = argd.hypot(argd2), MF_ILOGB => {
ret.type_ = MN_INTEGER;
ret.l = unsafe { ilogb(argd) } as i64;
}
MF_INT => {
ret.type_ = MN_INTEGER;
ret.l = argd as i64;
}
MF_ISINF => {
ret.type_ = MN_INTEGER;
ret.l = argd.is_infinite() as i64;
}
MF_ISNAN => {
ret.type_ = MN_INTEGER;
ret.l = argd.is_nan() as i64;
}
MF_J0 => retd = unsafe { j0(argd) }, MF_J1 => retd = unsafe { j1(argd) }, MF_JN => retd = unsafe { jn(argi, argd2) }, MF_LDEXP => retd = unsafe { ldexp(argd, argi) }, MF_LGAMMA => retd = unsafe { lgamma(argd) }, MF_LOG => retd = argd.ln(), MF_LOG10 => retd = argd.log10(), MF_LOG1P => retd = unsafe { log1p(argd) }, MF_LOG2 => retd = argd.log2(), MF_LOGB => retd = unsafe { logb(argd) }, MF_NEXTAFTER => retd = unsafe { nextafter(argd, argd2) }, MF_RINT => retd = unsafe { rint(argd) }, MF_SCALB => retd = unsafe { scalbn(argd, argi) }, MF_SIGNGAM => {
ret.type_ = MN_INTEGER;
ret.l = 0; }
MF_SIN => retd = argd.sin(), MF_SINH => retd = argd.sinh(), MF_SQRT => retd = argd.sqrt(), MF_TAN => retd = argd.tan(), MF_TANH => retd = argd.tanh(), MF_Y0 => retd = unsafe { y0(argd) }, MF_Y1 => retd = unsafe { y1(argd) }, MF_YN => retd = unsafe { yn(argi, argd2) }, _ => { }
}
if (id & tflag(TF_NOASS)) == 0 {
ret.d = retd; }
ret }
static MODULE_FEATURES: OnceLock<Mutex<features>> = OnceLock::new();
fn featuresarray(_m: *const module, _f: &Mutex<features>) -> Vec<String> {
vec![
"f:abs".to_string(),
"f:acos".to_string(),
"f:acosh".to_string(),
"f:asin".to_string(),
"f:asinh".to_string(),
"f:atan".to_string(),
"f:atanh".to_string(),
"f:cbrt".to_string(),
"f:ceil".to_string(),
"f:copysign".to_string(),
"f:cos".to_string(),
"f:cosh".to_string(),
"f:erf".to_string(),
"f:erfc".to_string(),
"f:exp".to_string(),
"f:expm1".to_string(),
"f:fabs".to_string(),
"f:float".to_string(),
"f:floor".to_string(),
"f:fmod".to_string(),
"f:gamma".to_string(),
"f:hypot".to_string(),
"f:ilogb".to_string(),
"f:int".to_string(),
"f:isinf".to_string(),
"f:isnan".to_string(),
"f:j0".to_string(),
"f:j1".to_string(),
"f:jn".to_string(),
"f:ldexp".to_string(),
"f:lgamma".to_string(),
"f:log".to_string(),
"f:log10".to_string(),
"f:log1p".to_string(),
"f:log2".to_string(),
"f:logb".to_string(),
"f:nextafter".to_string(),
"f:rint".to_string(),
"f:scalb".to_string(),
"f:signgam".to_string(),
"f:sin".to_string(),
"f:sinh".to_string(),
"f:sqrt".to_string(),
"f:tan".to_string(),
"f:tanh".to_string(),
"f:y0".to_string(),
"f:y1".to_string(),
"f:yn".to_string(),
]
}
fn handlefeatures(
_m: *const module,
_f: &Mutex<features>,
enables: &mut Option<Vec<i32>>,
) -> i32 {
if enables.is_none() {
*enables = Some(vec![1; 48]);
}
0
}
fn setfeatureenables(_m: *const module, _f: &Mutex<features>, _e: Option<&[i32]>) -> i32 {
0
}
fn module_features() -> &'static Mutex<features> {
MODULE_FEATURES.get_or_init(|| {
Mutex::new(features {
bn_list: None,
bn_size: 0,
cd_list: None,
cd_size: 0,
mf_list: None,
mf_size: 48,
pd_list: None,
pd_size: 0,
n_abstract: 0,
})
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_math_func_acos() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: 1.0,
type_: MN_FLOAT,
}];
let r = math_func("acos", 1, &argv, MF_ACOS);
assert!((r.type_ == MN_FLOAT));
assert!((r.d - 0.0).abs() < 1e-9);
}
#[test]
fn test_math_func_atan_two_args() {
let _g = crate::test_util::global_state_lock();
let argv = [
mnumber {
l: 0,
d: 1.0,
type_: MN_FLOAT,
},
mnumber {
l: 0,
d: 1.0,
type_: MN_FLOAT,
},
];
let r = math_func("atan", 2, &argv, MF_ATAN);
assert!((r.type_ == MN_FLOAT));
assert!((r.d - std::f64::consts::FRAC_PI_4).abs() < 1e-9);
}
#[test]
fn test_math_func_abs_int_preserves_type() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: -7,
d: 0.0,
type_: MN_INTEGER,
}];
let r = math_func("abs", 1, &argv, MF_ABS | tflag(TF_NOCONV | TF_NOASS));
assert!((r.type_ == MN_INTEGER));
assert_eq!(r.l, 7);
}
#[test]
fn test_math_func_int_truncates() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: 3.7,
type_: MN_FLOAT,
}];
let r = math_func("int", 1, &argv, MF_INT | tflag(TF_NOASS));
assert!((r.type_ == MN_INTEGER));
assert_eq!(r.l, 3);
}
#[test]
fn test_math_func_isnan() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: f64::NAN,
type_: MN_FLOAT,
}];
let r = math_func("isnan", 1, &argv, MF_ISNAN | tflag(TF_NOASS));
assert_eq!(r.l, 1);
}
#[test]
fn test_math_string_rand48_in_range() {
let _g = crate::test_util::global_state_lock();
let r = math_string("rand48", "", MS_RAND48);
assert!((r.type_ == MN_FLOAT));
assert!((0.0..1.0).contains(&r.d));
}
#[test]
fn math_func_cos_of_zero_is_one() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: 0.0,
type_: MN_FLOAT,
}];
let r = math_func("cos", 1, &argv, MF_COS);
assert_eq!(r.type_, MN_FLOAT);
assert!((r.d - 1.0).abs() < 1e-9);
}
#[test]
fn math_func_sin_of_zero_is_zero() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: 0.0,
type_: MN_FLOAT,
}];
let r = math_func("sin", 1, &argv, MF_SIN);
assert_eq!(r.type_, MN_FLOAT);
assert!(r.d.abs() < 1e-9, "sin(0) = {}", r.d);
}
#[test]
fn math_func_sqrt_of_four_is_two() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: 4.0,
type_: MN_FLOAT,
}];
let r = math_func("sqrt", 1, &argv, MF_SQRT);
assert_eq!(r.type_, MN_FLOAT);
assert!((r.d - 2.0).abs() < 1e-9, "sqrt(4) = {}", r.d);
}
#[test]
fn math_func_exp_of_zero_is_one() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: 0.0,
type_: MN_FLOAT,
}];
let r = math_func("exp", 1, &argv, MF_EXP);
assert_eq!(r.type_, MN_FLOAT);
assert!((r.d - 1.0).abs() < 1e-9);
}
#[test]
fn math_func_log_of_one_is_zero() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: 1.0,
type_: MN_FLOAT,
}];
let r = math_func("log", 1, &argv, MF_LOG);
assert_eq!(r.type_, MN_FLOAT);
assert!(r.d.abs() < 1e-9, "log(1) = {}", r.d);
}
#[test]
fn math_func_floor_rounds_down() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: 3.7,
type_: MN_FLOAT,
}];
let r = math_func("floor", 1, &argv, MF_FLOOR);
assert_eq!(r.type_, MN_FLOAT);
assert_eq!(r.d, 3.0);
}
#[test]
fn math_func_ceil_rounds_up() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: 3.1,
type_: MN_FLOAT,
}];
let r = math_func("ceil", 1, &argv, MF_CEIL);
assert_eq!(r.type_, MN_FLOAT);
assert_eq!(r.d, 4.0);
}
#[test]
fn math_func_fabs_preserves_float_type() {
let _g = crate::test_util::global_state_lock();
let argv = [mnumber {
l: 0,
d: -2.5,
type_: MN_FLOAT,
}];
let r = math_func("fabs", 1, &argv, MF_FABS);
assert_eq!(r.type_, MN_FLOAT);
assert_eq!(r.d, 2.5);
}
#[test]
fn math_func_isinf_classifies_correctly() {
let _g = crate::test_util::global_state_lock();
let argv_inf = [mnumber {
l: 0,
d: f64::INFINITY,
type_: MN_FLOAT,
}];
let r_inf = math_func("isinf", 1, &argv_inf, MF_ISINF | tflag(TF_NOASS));
assert_eq!(r_inf.l, 1, "isinf(+inf) must be 1");
let argv_fin = [mnumber {
l: 0,
d: 1.5,
type_: MN_FLOAT,
}];
let r_fin = math_func("isinf", 1, &argv_fin, MF_ISINF | tflag(TF_NOASS));
assert_eq!(r_fin.l, 0, "isinf(finite) must be 0");
}
#[test]
fn math_string_unknown_id_does_not_panic() {
let _g = crate::test_util::global_state_lock();
let _ = math_string("nope", "", 9999);
}
#[test]
fn module_lifecycle_shims_all_return_zero() {
let _g = crate::test_util::global_state_lock();
let m: *const module = std::ptr::null();
assert_eq!(setup_(m), 0);
assert_eq!(boot_(m), 0);
assert_eq!(cleanup_(m), 0);
assert_eq!(finish_(m), 0);
}
fn mn_int(v: i64) -> mnumber {
mnumber { l: v, d: 0.0, type_: MN_INTEGER }
}
fn mn_float(v: f64) -> mnumber {
mnumber { l: 0, d: v, type_: MN_FLOAT }
}
#[test]
fn math_func_abs_integer_input_preserves_int_type() {
let _g = crate::test_util::global_state_lock();
let r = math_func("abs", 1, &[mn_int(-5)], MF_ABS);
assert_eq!(r.type_, MN_INTEGER);
assert_eq!(r.l, 5);
}
#[test]
fn math_func_abs_float_input_preserves_float_type_anchored() {
let _g = crate::test_util::global_state_lock();
let r = math_func("abs", 1, &[mn_float(-3.14)], MF_ABS);
assert_eq!(r.type_, MN_FLOAT);
assert!(
(r.d - 3.14).abs() < 1e-9,
"abs(-3.14) must be 3.14; got {} (zsh: 3.14)",
r.d
);
}
#[test]
fn math_func_abs_positive_input_unchanged() {
let _g = crate::test_util::global_state_lock();
let r = math_func("abs", 1, &[mn_int(5)], MF_ABS);
assert_eq!(r.l, 5);
}
#[test]
fn math_func_sqrt_of_sixteen_is_four() {
let _g = crate::test_util::global_state_lock();
let r = math_func("sqrt", 1, &[mn_float(16.0)], MF_SQRT);
assert_eq!(r.type_, MN_FLOAT);
assert!((r.d - 4.0).abs() < 1e-9);
}
#[test]
fn math_func_sqrt_of_zero_is_zero() {
let _g = crate::test_util::global_state_lock();
let r = math_func("sqrt", 1, &[mn_float(0.0)], MF_SQRT);
assert!(r.d.abs() < 1e-9);
}
#[test]
fn math_func_sqrt_of_two_is_root_two() {
let _g = crate::test_util::global_state_lock();
let r = math_func("sqrt", 1, &[mn_float(2.0)], MF_SQRT);
assert!((r.d - std::f64::consts::SQRT_2).abs() < 1e-9);
}
#[test]
fn math_func_floor_negative_rounds_toward_neg_infinity() {
let _g = crate::test_util::global_state_lock();
let r = math_func("floor", 1, &[mn_float(-2.3)], MF_FLOOR);
assert!((r.d - (-3.0)).abs() < 1e-9);
}
#[test]
fn math_func_ceil_negative_rounds_toward_pos_infinity() {
let _g = crate::test_util::global_state_lock();
let r = math_func("ceil", 1, &[mn_float(-2.7)], MF_CEIL);
assert!((r.d - (-2.0)).abs() < 1e-9);
}
#[test]
fn math_func_sin_of_pi_over_two_is_one() {
let _g = crate::test_util::global_state_lock();
let r = math_func("sin", 1, &[mn_float(std::f64::consts::FRAC_PI_2)], MF_SIN);
assert!((r.d - 1.0).abs() < 1e-9);
}
#[test]
fn math_func_log_of_e_is_one() {
let _g = crate::test_util::global_state_lock();
let r = math_func("log", 1, &[mn_float(std::f64::consts::E)], MF_LOG);
assert!((r.d - 1.0).abs() < 1e-9);
}
#[test]
fn math_func_log10_of_hundred_is_two() {
let _g = crate::test_util::global_state_lock();
let r = math_func("log10", 1, &[mn_float(100.0)], MF_LOG10);
assert!((r.d - 2.0).abs() < 1e-9);
}
#[test]
fn math_func_log2_of_eight_is_three() {
let _g = crate::test_util::global_state_lock();
let r = math_func("log2", 1, &[mn_float(8.0)], MF_LOG2);
assert!((r.d - 3.0).abs() < 1e-9);
}
#[test]
fn math_func_sqrt_int_input_coerces_to_float() {
let _g = crate::test_util::global_state_lock();
let r = math_func("sqrt", 1, &[mn_int(16)], MF_SQRT);
assert_eq!(r.type_, MN_FLOAT);
assert!((r.d - 4.0).abs() < 1e-9);
}
#[test]
fn mathfunc_corpus_abs_negative_float() {
let _g = crate::test_util::global_state_lock();
let r = math_func("abs", 1, &[mn_float(-5.0)], MF_ABS);
assert!((r.d.abs() - 5.0).abs() < 1e-9, "|−5.0| = 5.0, got {:?}", r.d);
}
#[test]
fn mathfunc_corpus_cos_zero_is_one() {
let _g = crate::test_util::global_state_lock();
let r = math_func("cos", 1, &[mn_float(0.0)], MF_COS);
assert!((r.d - 1.0).abs() < 1e-9);
}
#[test]
fn mathfunc_corpus_sin_zero_is_zero() {
let _g = crate::test_util::global_state_lock();
let r = math_func("sin", 1, &[mn_float(0.0)], MF_SIN);
assert!(r.d.abs() < 1e-9, "sin(0)=0, got {}", r.d);
}
#[test]
fn mathfunc_corpus_exp_zero_is_one() {
let _g = crate::test_util::global_state_lock();
let r = math_func("exp", 1, &[mn_float(0.0)], MF_EXP);
assert!((r.d - 1.0).abs() < 1e-9);
}
#[test]
fn mathfunc_corpus_ceil_rounds_up() {
let _g = crate::test_util::global_state_lock();
let r = math_func("ceil", 1, &[mn_float(2.3)], MF_CEIL);
assert!((r.d - 3.0).abs() < 1e-9, "ceil(2.3)=3.0, got {}", r.d);
}
#[test]
fn mathfunc_corpus_floor_rounds_down() {
let _g = crate::test_util::global_state_lock();
let r = math_func("floor", 1, &[mn_float(2.7)], MF_FLOOR);
assert!((r.d - 2.0).abs() < 1e-9, "floor(2.7)=2.0, got {}", r.d);
}
#[test]
fn mathfunc_corpus_fabs_negative() {
let _g = crate::test_util::global_state_lock();
let r = math_func("fabs", 1, &[mn_float(-7.5)], MF_FABS);
assert!((r.d - 7.5).abs() < 1e-9);
}
#[test]
fn mathfunc_corpus_int_truncates_toward_zero() {
let _g = crate::test_util::global_state_lock();
let r = math_func("int", 1, &[mn_float(3.7)], MF_INT);
assert_eq!(r.l, 3, "int(3.7) = 3, got {}", r.l);
}
#[test]
fn mathfunc_corpus_int_truncates_negative_toward_zero() {
let _g = crate::test_util::global_state_lock();
let r = math_func("int", 1, &[mn_float(-3.7)], MF_INT);
assert_eq!(r.l, -3, "int(-3.7) = -3, got {}", r.l);
}
#[test]
fn mathfunc_corpus_float_promotes_int() {
let _g = crate::test_util::global_state_lock();
let r = math_func("float", 1, &[mn_int(5)], MF_FLOAT);
assert_eq!(r.type_, MN_FLOAT, "result is float-typed");
assert!((r.d - 5.0).abs() < 1e-9);
}
}