]> Repositorios git - scryer-prolog.git/commitdiff
Fix round() losing precision on bigints
authorEmilie Burgun <[email protected]>
Fri, 17 Jan 2025 22:33:09 +0000 (23:33 +0100)
committerEmilie Burgun <[email protected]>
Sun, 26 Jan 2025 23:05:30 +0000 (00:05 +0100)
The original issue can be reproduced with `X is round(2 ^ 54 + 1) - 2 ^ 54, X = 1.`

src/machine/arithmetic_ops.rs

index 290ccc37ed338ca818cd6a3b2c09a3a784bf8e45..2d1bdc656f085ce10f12a856dc48c12963d66309 100644 (file)
@@ -1072,16 +1072,22 @@ pub(crate) fn truncate(n: Number, arena: &mut Arena) -> Number {
     }
 }
 
-pub(crate) fn round(n: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
-    let stub_gen = || {
-        let is_atom = atom!("is");
-        functor_stub(is_atom, 2)
+pub(crate) fn round(num: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+    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<Number, MachineStubGen> {