From: Emilie Burgun Date: Fri, 17 Jan 2025 22:33:09 +0000 (+0100) Subject: Fix round() losing precision on bigints X-Git-Tag: v0.10.0~77^2~4 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=d3361c16d81567db2426043a4c52ed30495af040;p=scryer-prolog.git Fix round() losing precision on bigints The original issue can be reproduced with `X is round(2 ^ 54 + 1) - 2 ^ 54, X = 1.` --- diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 290ccc37..2d1bdc65 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1072,16 +1072,22 @@ pub(crate) fn truncate(n: Number, arena: &mut Arena) -> Number { } } -pub(crate) fn round(n: Number, arena: &mut Arena) -> Result { - let stub_gen = || { - let is_atom = atom!("is"); - functor_stub(is_atom, 2) +pub(crate) fn round(num: Number, arena: &mut Arena) -> Result { + let res = match num { + Number::Fixnum(_) | Number::Integer(_) => num, + Number::Rational(rat) => Number::arena_from(rat.round(), arena), + Number::Float(f) => Number::Float(OrderedFloat((*f).round())), }; - let result = add(n, Number::Float(OrderedFloat(0.5f64)), arena); - let result = try_numeric_result!(result, stub_gen)?; + // FIXME: make round/1 return EvalError + rnd_i(&res, arena).map_err(|err| -> MachineStubGen { + Box::new(move |machine_st| { + let eval_error = machine_st.evaluation_error(err); + let stub = functor_stub(atom!("round"), 1); - Ok(floor(result, arena)) + machine_st.error_form(eval_error, stub) + }) + }) } pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result {