From: Mark Thom Date: Sun, 27 Oct 2019 19:05:05 +0000 (-0600) Subject: add sign/1 (#216) and gcd/2 (#217) as evaluable functors, update the README X-Git-Tag: v0.8.116~11 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=e656e7fbae950fd7cbaff7030433d96fbe96445d;p=scryer-prolog.git add sign/1 (#216) and gcd/2 (#217) as evaluable functors, update the README --- diff --git a/README.md b/README.md index 28f254e2..0b8b564c 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,11 @@ Extend Scryer Prolog to include the following, among other features: - [x] Backtrackable and non-backtrackable global variables via `bb_get/2` `bb_put/2` (non-backtrackable) and `bb_b_put/2` (backtrackable). +- [ ] clp(B) and clp($\mathbb{Z}$) as builtin libraries (_in progress_). - [ ] Streams and predicates for stream control (_in progress_). - [ ] An incremental compacting garbage collector satisfying the five properties of "Precise Garbage Collection in Prolog." - [ ] Mode declarations. -- [ ] Extensions for clp(FD). ## Phase 3 @@ -134,7 +134,7 @@ The following predicates are built-in to Scryer. `abs/1`, `sin/1`, `cos/1`, `tan/1`, `asin/1`, `acos/1`, `atan/1`, `atan2/2`, `log/1`, `exp/1`, `sqrt/1`, `float/1`, `truncate/1`, `round/1`, `floor/1`, `ceiling/1`, `pi/0`, - `min/1`, `max/1` + `min/1`, `max/1`, `gcd/2`, `sign/1` * Comparison operators: `>`, `<`, `=<`, `>=`, `=:=`, `=\=`. * `(:)/2` * `(@>)/2` diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index 5ed87051..4c126d77 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -159,6 +159,7 @@ impl<'a> ArithmeticEvaluator<'a> { "round" => Ok(ArithmeticInstruction::Round(a1, t)), "ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)), "floor" => Ok(ArithmeticInstruction::Floor(a1, t)), + "sign" => Ok(ArithmeticInstruction::Sign(a1, t)), "\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)), _ => Err(ArithmeticError::NonEvaluableFunctor( Constant::Atom(name, None), @@ -192,6 +193,7 @@ impl<'a> ArithmeticEvaluator<'a> { "xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)), "mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)), "rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)), + "gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)), "atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)), _ => Err(ArithmeticError::NonEvaluableFunctor( Constant::Atom(name, None), diff --git a/src/prolog/instructions.rs b/src/prolog/instructions.rs index f8ffd99c..75a7d893 100644 --- a/src/prolog/instructions.rs +++ b/src/prolog/instructions.rs @@ -189,6 +189,8 @@ pub enum ArithmeticInstruction { Or(ArithmeticTerm, ArithmeticTerm, usize), Mod(ArithmeticTerm, ArithmeticTerm, usize), Rem(ArithmeticTerm, ArithmeticTerm, usize), + Gcd(ArithmeticTerm, ArithmeticTerm, usize), + Sign(ArithmeticTerm, usize), Cos(ArithmeticTerm, usize), Sin(ArithmeticTerm, usize), Tan(ArithmeticTerm, usize), @@ -314,6 +316,10 @@ impl ArithmeticInstruction { &ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => { arith_instr_bin_functor(h, "rem", at_1, at_2, t) } + &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, "gcd", at_1, at_2, t) + } + &ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t), &ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t), &ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t), &ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t), diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 16495c1e..5d6b5fbc 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -940,6 +940,7 @@ impl MachineState { "mod" => interms.push(Number::Integer(self.modulus(a1, a2)?)), "rem" => interms.push(Number::Integer(self.remainder(a1, a2)?)), "atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))), + "gcd" => interms.push(Number::Integer(self.gcd(a1, a2)?)), _ => { return Err(self.error_form(MachineError::instantiation_error(), caller)) } @@ -967,6 +968,7 @@ impl MachineState { "ceiling" => interms.push(Number::Integer(self.ceiling(a1))), "floor" => interms.push(Number::Integer(self.floor(a1))), "\\" => interms.push(Number::Integer(self.bitwise_complement(a1)?)), + "sign" => interms.push(Number::Integer(self.sign(a1))), _ => { return Err(self.error_form(MachineError::instantiation_error(), caller)) } @@ -1099,6 +1101,26 @@ impl MachineState { } } + fn gcd(&self, n1: Number, n2: Number) -> Result { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(n1.gcd(&n2)) + } + (Number::Float(f), _) | (_, Number::Float(f)) => { + let n = Addr::Con(Constant::Float(f)); + let stub = MachineError::functor_stub(clause_name!("gcd"), 2); + + Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub)) + } + (Number::Rational(r), _) | (_, Number::Rational(r)) => { + let n = Addr::Con(Constant::Rational(r)); + let stub = MachineError::functor_stub(clause_name!("gcd"), 2); + + Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub)) + } + } + } + fn float_pow(&self, n1: Number, n2: Number) -> Result { let f1 = result_f(&n1, rnd_f); let f2 = result_f(&n2, rnd_f); @@ -1355,6 +1377,16 @@ impl MachineState { } } + fn sign(&self, n: Number) -> Integer { + if n.is_positive() { + Integer::from(1) + } else if n.is_negative() { + Integer::from(0) + } else { + Integer::from(-1) + } + } + fn remainder(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(rem)"), 2); @@ -1440,6 +1472,13 @@ impl MachineState { self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2)); self.p += 1; } + &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + let n2 = try_or_fail!(self, self.get_number(a2)); + + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.gcd(n1, n2))); + self.p += 1; + } &ArithmeticInstruction::Pow(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); @@ -1477,6 +1516,12 @@ impl MachineState { self.interms[t - 1] = n1.abs(); self.p += 1; } + &ArithmeticInstruction::Sign(ref a1, t) => { + let n = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Integer(self.sign(n)); + self.p += 1; + } &ArithmeticInstruction::Neg(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); diff --git a/src/prolog/write.rs b/src/prolog/write.rs index 84df600c..03a884c8 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -352,6 +352,9 @@ impl fmt::Display for ArithmeticInstruction { &ArithmeticInstruction::RDiv(ref a1, ref a2, ref t) => { write!(f, "rdiv {}, {}, @{}", a1, a2, t) } + &ArithmeticInstruction::Gcd(ref a1, ref a2, ref t) => { + write!(f, "gcd {}, {}, @{}", a1, a2, t) + } &ArithmeticInstruction::Shl(ref a1, ref a2, ref t) => { write!(f, "shl {}, {}, @{}", a1, a2, t) } @@ -377,6 +380,7 @@ impl fmt::Display for ArithmeticInstruction { write!(f, "atan2 {}, {}, @{}", a1, a2, t) } &ArithmeticInstruction::Plus(ref a, ref t) => write!(f, "plus {}, @{}", a, t), + &ArithmeticInstruction::Sign(ref a, ref t) => write!(f, "sign {}, @{}", a, t), &ArithmeticInstruction::Neg(ref a, ref t) => write!(f, "neg {}, @{}", a, t), &ArithmeticInstruction::Cos(ref a, ref t) => write!(f, "cos {}, @{}", a, t), &ArithmeticInstruction::Sin(ref a, ref t) => write!(f, "sin {}, @{}", a, t),