add sign/1 (#216) and gcd/2 (#217) as evaluable functors, update the README

This commit is contained in:
Mark Thom
2019-10-27 13:05:05 -06:00
parent 0fdf0d8d06
commit e656e7fbae
5 changed files with 59 additions and 2 deletions

View File

@@ -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),

View File

@@ -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),

View File

@@ -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<Integer, MachineStub> {
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<Number, MachineStub> {
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<Integer, MachineStub> {
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));

View File

@@ -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),