diff --git a/distribution/std-lib/Base/src/Bench_Utils.enso b/distribution/std-lib/Base/src/Bench_Utils.enso index b3943ed4ee..6651fd0540 100644 --- a/distribution/std-lib/Base/src/Bench_Utils.enso +++ b/distribution/std-lib/Base/src/Bench_Utils.enso @@ -26,11 +26,6 @@ Number.times = act -> res = here.reverse_list (go Nil this) res -zeropad number = - txt = number.to_text - if number % 10 == number then "00" + txt else - if number % 100 == number then "0" + txt else txt - measure = ~act -> label -> iter_size -> num_iters -> single_call = _ -> x1 = System.nano_time @@ -41,6 +36,6 @@ measure = ~act -> label -> iter_size -> num_iters -> act_it_num = num_iters - it_num res = iter_size.times single_call avg = here.avg_list res - fmt = (avg / 1000000).to_text + "." + here.zeropad ((avg / 1000) % 1000) + fmt = (avg / 1000000).format "%.2f" IO.println (label + "/iteration:" + act_it_num.to_text + ": " + fmt + "ms") num_iters.times iteration diff --git a/distribution/std-lib/Base/src/Main.enso b/distribution/std-lib/Base/src/Main.enso index 0c7d953d87..4ab6585926 100644 --- a/distribution/std-lib/Base/src/Main.enso +++ b/distribution/std-lib/Base/src/Main.enso @@ -1,11 +1,13 @@ import Base.List import Base.Vector -from Builtins import Number, Unit +import Base.Number.Extensions +from Builtins import Unit, Number, Integer from Builtins export all from Base.List export Nil, Cons from Base.Vector export Vector +from Base.Number.Extensions export all hiding Math ## Represents a right-exclusive range of integer values. type Range @@ -42,5 +44,9 @@ type Range res = it initial this.start this.end res -## Creates a new right-exclusive range of integers from `this` to `n`. -Number.upto n = Range this n +type Math + +## The mathematical constant pi, equal to the ratio of a circle circumference + to its diameter. +Math.pi : Decimal +Math.pi = 3.141592653589793 diff --git a/distribution/std-lib/Base/src/Number/Extensions.enso b/distribution/std-lib/Base/src/Number/Extensions.enso new file mode 100644 index 0000000000..42b54f5402 --- /dev/null +++ b/distribution/std-lib/Base/src/Number/Extensions.enso @@ -0,0 +1,85 @@ +from Base import all +polyglot java import java.lang.Math +polyglot java import java.lang.String + +## Computes the inverse of the sine function + + Selects a value in the -pi/2 through pi/2 range. +Number.asin : Decimal +Number.asin = Math.asin [this.to_decimal] + +## Computes the inverse of the cosine function. + + Selects a value in the -pi/2 through pi/2 range. +Number.acos : Decimal +Number.acos = Math.acos [this.to_decimal] + +## Computes the inverse of the tangent function. + + Selects a value in the -pi/2 through pi/2 range. +Number.atan : Decimal +Number.atan = Math.atan [this.to_decimal] + +## Computes the argument (angle) in the conversion from cartesian + to polar coordinates. + + The returned angle is in the -pi through pi range. +Number.atan_2 : Number -> Decimal +Number.atan_2 y = Math.atan2 [this.to_decimal, y.to_decimal] + +## Computes the sine function. +Number.sin : Decimal +Number.sin = Math.sin [this.to_decimal] + +## Computes the cosine function. +Number.cos : Decimal +Number.cos = Math.cos [this.to_decimal] + +## Computes the tangent function. +Number.tan : Decimal +Number.tan = Math.tan [this.to_decimal] + +## Computes the hyperbolic sine function. +Number.sinh : Decimal +Number.sinh = Math.sinh [this.to_decimal] + +## Computes the hyperbolic cosine function. +Number.cosh : Decimal +Number.cosh = Math.cosh [this.to_decimal] + +## Computes the hyperbolic tangent function. +Number.tanh : Decimal +Number.tanh = Math.tanh [this.to_decimal] + +## Computes the exponential function. +Number.exp : Decimal +Number.exp = Math.exp [this.to_decimal] + +## Computes the natural logarithm function. +Number.ln : Decimal +Number.ln = Math.log [this.to_decimal] + +## Computes the square root of `this`. +Number.sqrt : Decimal +Number.sqrt = Math.sqrt [this.to_decimal] + +## Computes the `base`-log of `this`. +Number.log : Number -> Decimal +Number.log base = this.ln / base.ln + +## Converts a decimal value to a string, using the Java string formatting + syntax. + + TODO this should expose a more-user friendly API in the future. +Decimal.format : Text -> Text +Decimal.format fmt = String.format [fmt, this] + +## Creates a new right-exclusive range of integers from `this` to `n`. +Integer.upto : Integer -> Range +Integer.upto n = Range this n + +## Checks equality of numbers, using an `epsilon` value. + + Returns `True` when `this` and `that` are at most `epsilon` apart. +Number.equals : Number -> Number -> Boolean +Number.equals that epsilon = (this - that).abs <= epsilon diff --git a/distribution/std-lib/Base/src/Test.enso b/distribution/std-lib/Base/src/Test.enso index 433aa4c001..3f3098a334 100644 --- a/distribution/std-lib/Base/src/Test.enso +++ b/distribution/std-lib/Base/src/Test.enso @@ -1,5 +1,4 @@ -import Base.List -from Builtins import all +from Base import all ## The top-level entry point for a test suite. type Suite specs @@ -38,6 +37,13 @@ Any.should_equal that = case this == that of msg = this.to_text + " did not equal " + that.to_text + "." Panic.throw (Failure msg) +## Asserts that `this` is within `epsilon` from `that`. +Decimal.should_equal that (epsilon = 0) = case this.equals that epsilon of + True -> Success + False -> + msg = this.to_text + " did not equal " + that.to_text + "." + Panic.throw (Failure msg) + ## Asserts that the given `Boolean` is `True` Boolean.should_be_true = case this of True -> Success diff --git a/docs/semantics/numbers.md b/docs/semantics/numbers.md new file mode 100644 index 0000000000..eb1d879635 --- /dev/null +++ b/docs/semantics/numbers.md @@ -0,0 +1,66 @@ +--- +layout: developer-doc +title: Numbers +category: semantics +tags: [semantics, runtime, number] +order: 8 +--- + +# Numbers + +In order to enhance the user experience, Enso provides a number hierarchy, +encompassing both integers of unbound size and floating-point decimals. + + + +- [Number Types](#number-types) +- [Internal Representation](#internal-representation) +- [Type Conversions](#type-conversions) + + + +## Number Types + +The base number type in Enso is `Number`. It includes both integers and +floating-point numbers and is the basic type that should be used whenever +numerical computations are performed. Any method defined on the type `Number` is +automatically available on all types of numeric values. + +The hierarchy is further split into the `Integer` and `Decimal` types. `Integer` +is capable of representing values of unbound length. `Decimal` is capable of +representing IEEE 64-bit (double precision) floating numbers. + +Any method defined on `Integer` is available for all integers, while any method +defined on `Decimal` is available on all floating-point numbers. Methods defined +on `Integer` or `Decimal` take precedence over methods defined on `Number`, when +name resolution is performed. + +## Internal Representation + +Integers that can be represented in a 64-bit integer type are represented as +such. When a 64-bit representation would overflow (either by the result of +creating a large number literal or an arithmetic operation), it is represented +in a Java `BigInteger` type, thus becoming significantly slower than the 64-bit +representation. + +Decimals are represented using the Java `double` type. + +## Type Conversions + +Number literals that do not contain a decimal point, are treated as integers. +Other literals are interpreted as decimals (even if the fractional part is 0). + +Any arithmetic operation where at least one of the operands is a decimal will +result in a decimal result. + +Moreover, the default division operator `/` is implemented as floating-point +division and always returns a decimal. If the desired behavior is integral +division instead, the `Integer.div` method implements it. + +Another operator worth noting is the exponentiation operator (`^`). It will +always result in a decimal whenever either operand is decimal or the exponent is +negative. It will also return a float result when the exponent is outside the +64-bit integer range. + +There is a `Number.to_decimal` method, that allows converting any number to a +decimal. This is useful in certain high-performance and polyglot applications. diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java index 118ae51c53..6541e0a9bd 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/MethodResolverNode.java @@ -97,6 +97,16 @@ public abstract class MethodResolverNode extends Node { return function; } + @Specialization(guards = "cachedSymbol == symbol") + Function resolveDouble( + UnresolvedSymbol symbol, + double self, + @Cached(value = "symbol", allowUncached = true) UnresolvedSymbol cachedSymbol, + @Cached(value = "resolveMethodOnDouble(cachedSymbol)", allowUncached = true) + Function function) { + return function; + } + @Specialization(guards = {"cachedSymbol == symbol", "function != null"}) Function resolveBoolean( UnresolvedSymbol symbol, @@ -220,6 +230,14 @@ public abstract class MethodResolverNode extends Node { symbol); } + Function resolveMethodOnDouble(UnresolvedSymbol symbol) { + Number number = getBuiltins().number(); + return ensureMethodExists( + symbol.resolveFor(number.getDecimal(), number.getNumber(), getBuiltins().any()), + "Decimal", + symbol); + } + @CompilerDirectives.TruffleBoundary Function resolveMethodOnPrimBoolean(UnresolvedSymbol symbol, Context context) { Bool bool = context.getBuiltins().bool(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java new file mode 100644 index 0000000000..19cb2d58e3 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java @@ -0,0 +1,55 @@ +package org.enso.interpreter.node.expression.builtin.interop.syntax; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.ReportPolymorphism; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; + +/** + * Converts a value returned by a polyglot call back to a value that can be further used within Enso + * programs. + */ +@ReportPolymorphism +public abstract class HostValueToEnsoNode extends Node { + public static HostValueToEnsoNode build() { + return HostValueToEnsoNodeGen.create(); + } + + /** + * Converts an arbitrary value to a value usable within Enso code. + * + * @param o the value to convert. + * @return the Enso counterpart of the value. + */ + public abstract Object execute(Object o); + + @Specialization + double doFloat(float f) { + return f; + } + + @Specialization + long doInt(int i) { + return i; + } + + @Specialization + long doShort(short i) { + return i; + } + + @Specialization + long doByte(byte i) { + return i; + } + + @Specialization + long doChar(char i) { + return i; + } + + @Fallback + Object doOther(Object o) { + return o; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/MethodDispatchNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/MethodDispatchNode.java index 8ded578149..fc7af7c70d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/MethodDispatchNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/MethodDispatchNode.java @@ -1,9 +1,6 @@ package org.enso.interpreter.node.expression.builtin.interop.syntax; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Bind; -import com.oracle.truffle.api.dsl.ReportPolymorphism; -import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.*; import com.oracle.truffle.api.nodes.NodeInfo; @@ -17,6 +14,7 @@ import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.error.PanicException; +import org.enso.interpreter.runtime.scope.ModuleScope; import org.enso.interpreter.runtime.state.Stateful; import org.enso.interpreter.runtime.type.TypesGen; @@ -29,6 +27,7 @@ public abstract class MethodDispatchNode extends BuiltinRootNode { private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); + private @Child HostValueToEnsoNode hostValueToEnsoNode = HostValueToEnsoNode.build(); private final BranchProfile err = BranchProfile.create(); private @Child InvokeCallableNode invokeCallableNode = @@ -53,12 +52,12 @@ public abstract class MethodDispatchNode extends BuiltinRootNode { * @param frame current execution frame. * @return the result of converting input into a string. */ - @Specialization(guards = "symbol == cachedSymbol") + @Specialization(guards = "symbol.getScope() == cachedScope") public Stateful run( VirtualFrame frame, @Bind("getSymbol(frame)") UnresolvedSymbol symbol, - @Cached("symbol") UnresolvedSymbol cachedSymbol, - @Cached("buildToArray(cachedSymbol)") UnresolvedSymbol toArray) { + @Cached("symbol.getScope()") ModuleScope cachedScope, + @Cached("buildToArray(cachedScope)") UnresolvedSymbol toArray) { Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments()); Object callable = args[0]; Object state = Function.ArgumentsHelper.getState(frame.getArguments()); @@ -66,7 +65,8 @@ public abstract class MethodDispatchNode extends BuiltinRootNode { Stateful casted = invokeCallableNode.execute(toArray, frame, state, new Object[] {arguments}); try { Object[] castedArgs = TypesGen.expectArray(casted.getValue()).getItems(); - Object res = library.invokeMember(callable, symbol.getName(), castedArgs); + Object res = + hostValueToEnsoNode.execute(library.invokeMember(callable, symbol.getName(), castedArgs)); return new Stateful(casted.getState(), res); } catch (UnsupportedMessageException | ArityException @@ -78,8 +78,14 @@ public abstract class MethodDispatchNode extends BuiltinRootNode { } } - UnresolvedSymbol buildToArray(UnresolvedSymbol originalSymbol) { - return UnresolvedSymbol.build("to_array", originalSymbol.getScope()); + @Specialization + public Stateful runUncached(VirtualFrame frame) { + UnresolvedSymbol sym = getSymbol(frame); + return run(frame, sym, sym.getScope(), buildToArray(sym.getScope())); + } + + UnresolvedSymbol buildToArray(ModuleScope scope) { + return UnresolvedSymbol.build("to_array", scope); } UnresolvedSymbol getSymbol(VirtualFrame frame) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/AbsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/AbsNode.java new file mode 100644 index 0000000000..cecd81aa36 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/AbsNode.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.node.expression.builtin.number.bigInteger; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Big_Integer", name = "abs", description = "Big integer absolute value.") +public class AbsNode extends Node { + private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); + + Object execute(EnsoBigInteger _this) { + return toEnsoNumberNode.execute(BigIntegerOps.abs(_this.getValue())); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/AddNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/AddNode.java index 203932c30c..6fab3c2125 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/AddNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/AddNode.java @@ -29,6 +29,11 @@ public abstract class AddNode extends Node { return toEnsoNumberNode.execute(BigIntegerOps.add(_this.getValue(), that.getValue())); } + @Specialization + double doDouble(EnsoBigInteger _this, double that) { + return BigIntegerOps.toDouble(_this.getValue()) + that; + } + @Fallback Object doOther(EnsoBigInteger _this, Object that) { throw new TypeError("Unexpected type provided for argument `that` in Integer.+", this); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/DivNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/DivNode.java new file mode 100644 index 0000000000..bf1991544a --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/DivNode.java @@ -0,0 +1,36 @@ +package org.enso.interpreter.node.expression.builtin.number.bigInteger; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Big_Integer", name = "div", description = "Big integer integral division.") +public abstract class DivNode extends Node { + private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); + + abstract Object execute(EnsoBigInteger _this, Object that); + + static DivNode build() { + return DivNodeGen.create(); + } + + @Specialization + Object doLong(EnsoBigInteger _this, long that) { + return toEnsoNumberNode.execute(BigIntegerOps.divide(_this.getValue(), that)); + } + + @Specialization + Object doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) { + return toEnsoNumberNode.execute(BigIntegerOps.divide(_this.getValue(), that.getValue())); + } + + @Fallback + Object doOther(EnsoBigInteger _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.div", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/DivideNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/DivideNode.java index 8ca276dc5a..61d9116a93 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/DivideNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/DivideNode.java @@ -5,32 +5,34 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Big_Integer", name = "/", description = "Big integer division.") public abstract class DivideNode extends Node { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); - - abstract Object execute(EnsoBigInteger _this, Object that); + abstract double execute(EnsoBigInteger _this, Object that); static DivideNode build() { return DivideNodeGen.create(); } @Specialization - Object doLong(EnsoBigInteger _this, long that) { - return toEnsoNumberNode.execute(BigIntegerOps.divide(_this.getValue(), that)); + double doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) { + return BigIntegerOps.toDouble(_this.getValue()) / BigIntegerOps.toDouble(that.getValue()); } @Specialization - Object doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) { - return toEnsoNumberNode.execute(BigIntegerOps.divide(_this.getValue(), that.getValue())); + double doLong(EnsoBigInteger _this, long that) { + return BigIntegerOps.toDouble(_this.getValue()) / that; + } + + @Specialization + double doDouble(EnsoBigInteger _this, double that) { + return BigIntegerOps.toDouble(_this.getValue()) / that; } @Fallback - Object doOther(EnsoBigInteger _this, Object that) { + double doOther(EnsoBigInteger _this, Object that) { throw new TypeError("Unexpected type provided for argument `that` in Integer./", this); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/EqualsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/EqualsNode.java index 42c0dc594a..4c40f731b5 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/EqualsNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/EqualsNode.java @@ -21,6 +21,11 @@ public abstract class EqualsNode extends Node { return BigIntegerOps.equals(_this.getValue(), that.getValue()); } + @Specialization + boolean doDouble(EnsoBigInteger _this, double that) { + return BigIntegerOps.toDouble(_this.getValue()) == that; + } + @Fallback boolean doOther(EnsoBigInteger _this, Object that) { return false; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/GreaterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/GreaterNode.java new file mode 100644 index 0000000000..095aa7c21f --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/GreaterNode.java @@ -0,0 +1,39 @@ +package org.enso.interpreter.node.expression.builtin.number.bigInteger; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Big_Integer", name = ">", description = "Comparison of numbers.") +public abstract class GreaterNode extends Node { + + abstract boolean execute(EnsoBigInteger _this, Object that); + + static GreaterNode build() { + return GreaterNodeGen.create(); + } + + @Specialization + boolean doDouble(EnsoBigInteger _this, double that) { + return BigIntegerOps.toDouble(_this.getValue()) > that; + } + + @Specialization + boolean doLong(EnsoBigInteger _this, long that) { + return _this.getValue().signum() > 0; + } + + @Specialization + boolean doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) { + return BigIntegerOps.compare(_this.getValue(), that.getValue()) > 0; + } + + @Fallback + boolean doOther(EnsoBigInteger _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.>", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/GreaterOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/GreaterOrEqualNode.java new file mode 100644 index 0000000000..3209ad055f --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/GreaterOrEqualNode.java @@ -0,0 +1,39 @@ +package org.enso.interpreter.node.expression.builtin.number.bigInteger; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Big_Integer", name = ">=", description = "Comparison of numbers.") +public abstract class GreaterOrEqualNode extends Node { + + abstract boolean execute(EnsoBigInteger _this, Object that); + + static GreaterOrEqualNode build() { + return GreaterOrEqualNodeGen.create(); + } + + @Specialization + boolean doDouble(EnsoBigInteger _this, double that) { + return BigIntegerOps.toDouble(_this.getValue()) >= that; + } + + @Specialization + boolean doLong(EnsoBigInteger _this, long that) { + return _this.getValue().signum() > 0; + } + + @Specialization + boolean doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) { + return BigIntegerOps.compare(_this.getValue(), that.getValue()) >= 0; + } + + @Fallback + boolean doOther(EnsoBigInteger _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.>=", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/LessNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/LessNode.java new file mode 100644 index 0000000000..efd8af68fd --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/LessNode.java @@ -0,0 +1,39 @@ +package org.enso.interpreter.node.expression.builtin.number.bigInteger; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Big_Integer", name = "<", description = "Comparison of numbers.") +public abstract class LessNode extends Node { + + abstract boolean execute(EnsoBigInteger _this, Object that); + + static LessNode build() { + return LessNodeGen.create(); + } + + @Specialization + boolean doDouble(EnsoBigInteger _this, double that) { + return BigIntegerOps.toDouble(_this.getValue()) < that; + } + + @Specialization + boolean doLong(EnsoBigInteger _this, long that) { + return _this.getValue().signum() < 0; + } + + @Specialization + boolean doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) { + return BigIntegerOps.compare(_this.getValue(), that.getValue()) < 0; + } + + @Fallback + boolean doOther(EnsoBigInteger _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.<", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/LessOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/LessOrEqualNode.java new file mode 100644 index 0000000000..b40f7a8f70 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/LessOrEqualNode.java @@ -0,0 +1,39 @@ +package org.enso.interpreter.node.expression.builtin.number.bigInteger; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Big_Integer", name = "<=", description = "Comparison of numbers.") +public abstract class LessOrEqualNode extends Node { + + abstract boolean execute(EnsoBigInteger _this, Object that); + + static LessOrEqualNode build() { + return LessOrEqualNodeGen.create(); + } + + @Specialization + boolean doDouble(EnsoBigInteger _this, double that) { + return BigIntegerOps.toDouble(_this.getValue()) <= that; + } + + @Specialization + boolean doLong(EnsoBigInteger _this, long that) { + return _this.getValue().signum() < 0; + } + + @Specialization + boolean doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) { + return BigIntegerOps.compare(_this.getValue(), that.getValue()) <= 0; + } + + @Fallback + boolean doOther(EnsoBigInteger _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.<=", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/MultiplyNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/MultiplyNode.java index deeefaa445..f9b05d9293 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/MultiplyNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/MultiplyNode.java @@ -13,9 +13,9 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; public abstract class MultiplyNode extends Node { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); - abstract Object execute(EnsoBigInteger _this, Object that); + public abstract Object execute(EnsoBigInteger _this, Object that); - static MultiplyNode build() { + public static MultiplyNode build() { return MultiplyNodeGen.create(); } @@ -29,6 +29,11 @@ public abstract class MultiplyNode extends Node { return toEnsoNumberNode.execute(BigIntegerOps.multiply(_this.getValue(), that.getValue())); } + @Specialization + double doDouble(EnsoBigInteger _this, double that) { + return BigIntegerOps.toDouble(_this.getValue()) * that; + } + @Fallback Object doOther(EnsoBigInteger _this, Object that) { throw new TypeError("Unexpected type provided for argument `that` in Integer.*", this); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/PowNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/PowNode.java new file mode 100644 index 0000000000..9d19c3a0b3 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/PowNode.java @@ -0,0 +1,54 @@ +package org.enso.interpreter.node.expression.builtin.number.bigInteger; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Big_Integer", name = "^", description = "Big integer exponentiation.") +public abstract class PowNode extends Node { + private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); + + public abstract Object execute(EnsoBigInteger _this, Object that); + + public static PowNode build() { + return PowNodeGen.create(); + } + + @Specialization + Object doLong(EnsoBigInteger _this, long that) { + if (that == 0) { + return 1L; + } else if (that > 0) { + return toEnsoNumberNode.execute(BigIntegerOps.pow(_this.getValue(), that)); + } else { + return Math.pow(BigIntegerOps.toDouble(_this.getValue()), that); + } + } + + @Specialization + Object doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) { + if (that.getValue().signum() > 0) { + return Math.pow( + BigIntegerOps.toDouble(_this.getValue()), BigIntegerOps.toDouble(that.getValue())); + } else if (that.getValue().signum() == 0) { + return 1.0D; + } else { + return 0.0D; + } + } + + @Specialization + double doDouble(EnsoBigInteger _this, double that) { + return Math.pow(BigIntegerOps.toDouble(_this.getValue()), that); + } + + @Fallback + Object doOther(EnsoBigInteger _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.^", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/SubtractNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/SubtractNode.java index 9a90267e32..5edae0d188 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/SubtractNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/SubtractNode.java @@ -29,6 +29,11 @@ public abstract class SubtractNode extends Node { return toEnsoNumberNode.execute(BigIntegerOps.subtract(_this.getValue(), that.getValue())); } + @Specialization + double doDouble(EnsoBigInteger _this, double that) { + return BigIntegerOps.toDouble(_this.getValue()) - that; + } + @Fallback Object doOther(EnsoBigInteger _this, Object that) { throw new TypeError("Unexpected type provided for argument `that` in Integer.-", this); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/ToDecimalNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/ToDecimalNode.java new file mode 100644 index 0000000000..9ccb640818 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/bigInteger/ToDecimalNode.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.node.expression.builtin.number.bigInteger; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod( + type = "Big_Integer", + name = "to_decimal", + description = "Conversion of integers to decimals") +public class ToDecimalNode extends Node { + double execute(EnsoBigInteger _this) { + return BigIntegerOps.toDouble(_this.getValue()); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AbsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AbsNode.java new file mode 100644 index 0000000000..607f6df5ef --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AbsNode.java @@ -0,0 +1,11 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; + +@BuiltinMethod(type = "Decimal", name = "abs", description = "Absolute value of a number.") +public class AbsNode extends Node { + double execute(double _this) { + return Math.abs(_this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java new file mode 100644 index 0000000000..dfbede92ae --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = "+", description = "Addition of numbers.") +public abstract class AddNode extends Node { + abstract double execute(double _this, Object that); + + static AddNode build() { + return AddNodeGen.create(); + } + + @Specialization + double doDouble(double _this, double that) { + return _this + that; + } + + @Specialization + double doLong(double _this, long that) { + return _this + that; + } + + @Specialization + double doBigInteger(double _this, EnsoBigInteger that) { + return _this + BigIntegerOps.toDouble(that.getValue()); + } + + @Fallback + double doOther(double _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Decimal.+", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java new file mode 100644 index 0000000000..d6ed686ad6 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = "/", description = "Division of numbers.") +public abstract class DivideNode extends Node { + abstract double execute(double _this, Object that); + + static DivideNode build() { + return DivideNodeGen.create(); + } + + @Specialization + double doDouble(double _this, double that) { + return _this / that; + } + + @Specialization + double doLong(double _this, long that) { + return _this / that; + } + + @Specialization + double doBigInteger(double _this, EnsoBigInteger that) { + return _this / BigIntegerOps.toDouble(that.getValue()); + } + + @Fallback + double doOther(double _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Decimal./", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/EqualsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/EqualsNode.java new file mode 100644 index 0000000000..2881719169 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/EqualsNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = "==", description = "Equality on numbers.") +public abstract class EqualsNode extends Node { + + abstract boolean execute(double _this, Object that); + + static EqualsNode build() { + return EqualsNodeGen.create(); + } + + @Specialization + boolean doDouble(double _this, double that) { + return _this == that; + } + + @Specialization + boolean doLong(double _this, long that) { + return _this == (double) that; + } + + @Specialization + boolean doBigInteger(double _this, EnsoBigInteger that) { + return _this == BigIntegerOps.toDouble(that.getValue()); + } + + @Fallback + boolean doOther(double _this, Object that) { + return false; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java new file mode 100644 index 0000000000..fe5538ada2 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java @@ -0,0 +1,40 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = ">", description = "Comparison of numbers.") +public abstract class GreaterNode extends Node { + + abstract boolean execute(double _this, Object that); + + static GreaterNode build() { + return GreaterNodeGen.create(); + } + + @Specialization + boolean doDouble(double _this, double that) { + return _this > that; + } + + @Specialization + boolean doLong(double _this, long that) { + return _this > (double) that; + } + + @Specialization + boolean doBigInteger(double _this, EnsoBigInteger that) { + return _this > BigIntegerOps.toDouble(that.getValue()); + } + + @Fallback + boolean doOther(double _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Decimal.>", this); + + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java new file mode 100644 index 0000000000..1d1e0e1306 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java @@ -0,0 +1,39 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = ">=", description = "Comparison of numbers.") +public abstract class GreaterOrEqualNode extends Node { + + abstract boolean execute(double _this, Object that); + + static GreaterOrEqualNode build() { + return GreaterOrEqualNodeGen.create(); + } + + @Specialization + boolean doDouble(double _this, double that) { + return _this >= that; + } + + @Specialization + boolean doLong(double _this, long that) { + return _this >= (double) that; + } + + @Specialization + boolean doBigInteger(double _this, EnsoBigInteger that) { + return _this >= BigIntegerOps.toDouble(that.getValue()); + } + + @Fallback + boolean doOther(double _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Decimal.>=", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java new file mode 100644 index 0000000000..1e07296f43 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java @@ -0,0 +1,39 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = "<", description = "Comparison of numbers.") +public abstract class LessNode extends Node { + + abstract boolean execute(double _this, Object that); + + static LessNode build() { + return LessNodeGen.create(); + } + + @Specialization + boolean doDouble(double _this, double that) { + return _this < that; + } + + @Specialization + boolean doLong(double _this, long that) { + return _this < (double) that; + } + + @Specialization + boolean doBigInteger(double _this, EnsoBigInteger that) { + return _this < BigIntegerOps.toDouble(that.getValue()); + } + + @Fallback + boolean doOther(double _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Decimal.<", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java new file mode 100644 index 0000000000..81cc1f55ea --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java @@ -0,0 +1,39 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = "<=", description = "Comparison of numbers.") +public abstract class LessOrEqualNode extends Node { + + abstract boolean execute(double _this, Object that); + + static LessOrEqualNode build() { + return LessOrEqualNodeGen.create(); + } + + @Specialization + boolean doDouble(double _this, double that) { + return _this <= that; + } + + @Specialization + boolean doLong(double _this, long that) { + return _this <= (double) that; + } + + @Specialization + boolean doBigInteger(double _this, EnsoBigInteger that) { + return _this <= BigIntegerOps.toDouble(that.getValue()); + } + + @Fallback + boolean doOther(double _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Decimal.<=", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java new file mode 100644 index 0000000000..b85528ecfd --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java @@ -0,0 +1,36 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = "*", description = "Multiplication of numbers.") +public abstract class MultiplyNode extends Node { + abstract double execute(double _this, Object that); + + static MultiplyNode build() { + return MultiplyNodeGen.create(); + } + + @Specialization + double doDouble(double _this, double that) { return _this * that;} + + @Specialization + double doLong(double _this, long that) { + return _this * that; + } + + @Specialization + double doBigInteger(double _this, EnsoBigInteger that) { + return _this * BigIntegerOps.toDouble(that.getValue()); + } + + @Fallback + double doOther(double _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Decimal.*", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/NegateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/NegateNode.java new file mode 100644 index 0000000000..40c50d453e --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/NegateNode.java @@ -0,0 +1,11 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; + +@BuiltinMethod(type = "Decimal", name = "negate", description = "Negation for numbers.") +public class NegateNode extends Node { + double execute(double _this) { + return -_this; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java new file mode 100644 index 0000000000..60ddef0a6b --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = "^", description = "Exponentiation of numbers.") +public abstract class PowNode extends Node { + abstract double execute(double _this, Object that); + + static PowNode build() { + return PowNodeGen.create(); + } + + @Specialization + double doDouble(double _this, double that) { + return Math.pow(_this, that); + } + + @Specialization + double doLong(double _this, long that) { + return Math.pow(_this, that); + } + + @Specialization + double doBigInteger(double _this, EnsoBigInteger that) { + return Math.pow(_this, BigIntegerOps.toDouble(that.getValue())); + } + + @Fallback + double doOther(double _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Decimal.^", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java new file mode 100644 index 0000000000..764224c7bb --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Decimal", name = "-", description = "Subtraction of numbers.") +public abstract class SubtractNode extends Node { + abstract double execute(double _this, Object that); + + static SubtractNode build() { + return SubtractNodeGen.create(); + } + + @Specialization + double doDouble(double _this, double that) { + return _this - that; + } + + @Specialization + double doLong(double _this, long that) { + return _this - that; + } + + @Specialization + double doBigInteger(double _this, EnsoBigInteger that) { + return _this - BigIntegerOps.toDouble(that.getValue()); + } + + @Fallback + double doOther(double _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Decimal.-", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ToDecimalNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ToDecimalNode.java new file mode 100644 index 0000000000..bf7a2ef6be --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ToDecimalNode.java @@ -0,0 +1,16 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod( + type = "Decimal", + name = "to_decimal", + description = "Identity on decimals") +public class ToDecimalNode extends Node { + double execute(double _this) { + return _this; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/AbsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/AbsNode.java new file mode 100644 index 0000000000..a329e846ee --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/AbsNode.java @@ -0,0 +1,32 @@ +package org.enso.interpreter.node.expression.builtin.number.int64; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; + +@BuiltinMethod(type = "Small_Integer", name = "negate", description = "Negation for numbers.") +public abstract class AbsNode extends Node { + private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); + + static AbsNode build() { + return AbsNodeGen.create(); + } + + abstract Object execute(long _this); + + @Specialization(rewriteOn = ArithmeticException.class) + long doNormal(long _this) { + if (_this < 0) { + return Math.negateExact(_this); + } else { + return _this; + } + } + + @Specialization + Object doOverflow(long _this) { + return toEnsoNumberNode.execute(BigIntegerOps.abs(_this)); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/AddNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/AddNode.java index d629f34dea..d5d6805a19 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/AddNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/AddNode.java @@ -9,7 +9,7 @@ import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNod import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.number.EnsoBigInteger; -@BuiltinMethod(type = "Int_64", name = "+", description = "Addition of numbers.") +@BuiltinMethod(type = "Small_Integer", name = "+", description = "Addition of numbers.") public abstract class AddNode extends Node { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); @@ -29,6 +29,11 @@ public abstract class AddNode extends Node { return toEnsoNumberNode.execute(BigIntegerOps.add(_this, that)); } + @Specialization + double doDouble(long _this, double that) { + return _this + that; + } + @Specialization Object doBigInteger(long _this, EnsoBigInteger that) { return toEnsoNumberNode.execute(BigIntegerOps.add(that.getValue(), _this)); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/DivNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/DivNode.java new file mode 100644 index 0000000000..c0cc3c46d1 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/DivNode.java @@ -0,0 +1,32 @@ +package org.enso.interpreter.node.expression.builtin.number.int64; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Small_Integer", name = "div", description = "Division of numbers.") +public abstract class DivNode extends Node { + abstract Object execute(long _this, Object that); + + static DivNode build() { + return DivNodeGen.create(); + } + + @Specialization + long doLong(long _this, long that) { + return _this / that; + } + + @Specialization + long doBigInteger(long _this, EnsoBigInteger that) { + return 0L; + } + + @Fallback + Object doOther(long _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.div", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/DivideNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/DivideNode.java index 4c610e865f..3266a15928 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/DivideNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/DivideNode.java @@ -4,29 +4,35 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.number.EnsoBigInteger; -@BuiltinMethod(type = "Int_64", name = "/", description = "Division of numbers.") +@BuiltinMethod(type = "Small_Integer", name = "/", description = "Division of numbers.") public abstract class DivideNode extends Node { - abstract Object execute(long _this, Object that); + abstract double execute(long _this, Object that); static DivideNode build() { return DivideNodeGen.create(); } @Specialization - long doLong(long _this, long that) { + double doLong(long _this, long that) { + return ((double) _this) / ((double) that); + } + + @Specialization + double doDouble(long _this, double that) { return _this / that; } @Specialization - long doBigInteger(long _this, EnsoBigInteger that) { - return 0L; + double doBigInteger(long _this, EnsoBigInteger that) { + return ((double) _this) / BigIntegerOps.toDouble(that.getValue()); } @Fallback - Object doOther(long _this, Object that) { + double doOther(long _this, Object that) { throw new TypeError("Unexpected type provided for argument `that` in Integer./", this); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/EqualsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/EqualsNode.java index f5bc924883..07614ab5db 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/EqualsNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/EqualsNode.java @@ -5,7 +5,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; -@BuiltinMethod(type = "Int_64", name = "==", description = "Equality on numbers.") +@BuiltinMethod(type = "Small_Integer", name = "==", description = "Equality on numbers.") public abstract class EqualsNode extends Node { abstract boolean execute(long _this, Object that); @@ -19,6 +19,11 @@ public abstract class EqualsNode extends Node { return _this == that; } + @Specialization + boolean doDouble(long _this, double that) { + return (double) _this == that; + } + @Fallback boolean doOther(long _this, Object that) { return false; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/GreaterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/GreaterNode.java new file mode 100644 index 0000000000..28af15adc1 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/GreaterNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.number.int64; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Small_Integer", name = ">", description = "Comparison of numbers.") +public abstract class GreaterNode extends Node { + + abstract boolean execute(long _this, Object that); + + static GreaterNode build() { + return GreaterNodeGen.create(); + } + + @Specialization + boolean doLong(long _this, long that) { + return _this > that; + } + + @Specialization + boolean doDouble(long _this, double that) { + return (double) _this > that; + } + + @Specialization + boolean doBigInteger(long _this, EnsoBigInteger that) { + return that.getValue().signum() < 0; + } + + @Fallback + boolean doOther(long _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.>", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/GreaterOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/GreaterOrEqualNode.java new file mode 100644 index 0000000000..38f3897606 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/GreaterOrEqualNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.number.int64; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Small_Integer", name = ">=", description = "Comparison of numbers.") +public abstract class GreaterOrEqualNode extends Node { + + abstract boolean execute(long _this, Object that); + + static GreaterOrEqualNode build() { + return GreaterOrEqualNodeGen.create(); + } + + @Specialization + boolean doLong(long _this, long that) { + return _this >= that; + } + + @Specialization + boolean doDouble(long _this, double that) { + return (double) _this >= that; + } + + @Specialization + boolean doBigInteger(long _this, EnsoBigInteger that) { + return that.getValue().signum() < 0; + } + + @Fallback + boolean doOther(long _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.>=", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/LessNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/LessNode.java new file mode 100644 index 0000000000..24a207cf83 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/LessNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.number.int64; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Small_Integer", name = "<", description = "Comparison of numbers.") +public abstract class LessNode extends Node { + + abstract boolean execute(long _this, Object that); + + static LessNode build() { + return LessNodeGen.create(); + } + + @Specialization + boolean doLong(long _this, long that) { + return _this < that; + } + + @Specialization + boolean doDouble(long _this, double that) { + return (double) _this < that; + } + + @Specialization + boolean doBigInteger(long _this, EnsoBigInteger that) { + return that.getValue().signum() > 0; + } + + @Fallback + boolean doOther(long _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.<", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/LessOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/LessOrEqualNode.java new file mode 100644 index 0000000000..2a7f7d4808 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/LessOrEqualNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.number.int64; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + +@BuiltinMethod(type = "Small_Integer", name = "<=", description = "Comparison of numbers.") +public abstract class LessOrEqualNode extends Node { + + abstract boolean execute(long _this, Object that); + + static LessOrEqualNode build() { + return LessOrEqualNodeGen.create(); + } + + @Specialization + boolean doLong(long _this, long that) { + return _this <= that; + } + + @Specialization + boolean doDouble(long _this, double that) { + return (double) _this <= that; + } + + @Specialization + boolean doBigInteger(long _this, EnsoBigInteger that) { + return that.getValue().signum() > 0; + } + + @Fallback + boolean doOther(long _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.<=", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/ModNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/ModNode.java index 4dff1669cf..b02b7ab76e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/ModNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/ModNode.java @@ -7,7 +7,7 @@ import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.number.EnsoBigInteger; -@BuiltinMethod(type = "Int_64", name = "%", description = "Modulo division of numbers.") +@BuiltinMethod(type = "Small_Integer", name = "%", description = "Modulo division of numbers.") public abstract class ModNode extends Node { abstract Object execute(long _this, Object that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/MultiplyNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/MultiplyNode.java index 7837e24d2d..b07ff8a0ed 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/MultiplyNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/MultiplyNode.java @@ -9,7 +9,7 @@ import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNod import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.number.EnsoBigInteger; -@BuiltinMethod(type = "Int_64", name = "*", description = "Multiplication of numbers.") +@BuiltinMethod(type = "Small_Integer", name = "*", description = "Multiplication of numbers.") public abstract class MultiplyNode extends Node { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); @@ -29,6 +29,11 @@ public abstract class MultiplyNode extends Node { return toEnsoNumberNode.execute(BigIntegerOps.multiply(_this, that)); } + @Specialization + double doDouble(long _this, double that) { + return ((double) _this) * that; + } + @Specialization Object doBigInteger(long _this, EnsoBigInteger that) { return toEnsoNumberNode.execute(BigIntegerOps.multiply(that.getValue(), _this)); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/NegateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/NegateNode.java index 37c1dc1b94..0573379e37 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/NegateNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/NegateNode.java @@ -6,7 +6,7 @@ import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; -@BuiltinMethod(type = "Int_64", name = "negate", description = "Negation for numbers.") +@BuiltinMethod(type = "Small_Integer", name = "negate", description = "Negation for numbers.") public abstract class NegateNode extends Node { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/PowNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/PowNode.java new file mode 100644 index 0000000000..bb86db132f --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/PowNode.java @@ -0,0 +1,78 @@ +package org.enso.interpreter.node.expression.builtin.number.int64; + +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; +import org.enso.interpreter.runtime.error.TypeError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; +import org.enso.interpreter.runtime.type.TypesGen; + +import java.math.BigInteger; + +@BuiltinMethod(type = "Small_Integer", name = "^", description = "Exponentation of numbers.") +public abstract class PowNode extends Node { + private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); + private @Child org.enso.interpreter.node.expression.builtin.number.int64.MultiplyNode + longMultiplyNode = + org.enso.interpreter.node.expression.builtin.number.int64.MultiplyNode.build(); + private @Child org.enso.interpreter.node.expression.builtin.number.bigInteger.MultiplyNode + bigIntMultiplyNode = + org.enso.interpreter.node.expression.builtin.number.bigInteger.MultiplyNode.build(); + private @Child org.enso.interpreter.node.expression.builtin.number.bigInteger.PowNode + bigIntPowNode = + org.enso.interpreter.node.expression.builtin.number.bigInteger.PowNode.build(); + + abstract Object execute(long _this, Object that); + + static PowNode build() { + return PowNodeGen.create(); + } + + @Specialization + Object doLong(long _this, long that) { + if (that < 0) { + return Math.pow(_this, that); + } else if (that == 0) { + return 1L; + } else { + Object res = 1L; + Object base = _this; + while (that > 0) { + if (that % 2 == 0) { + if (base instanceof Long) { + base = longMultiplyNode.execute((long) base, base); + } else { + base = bigIntMultiplyNode.execute((EnsoBigInteger) base, base); + } + that /= 2; + } else { + if (res instanceof Long) { + res = longMultiplyNode.execute((long) res, base); + } else { + res = bigIntMultiplyNode.execute((EnsoBigInteger) res, base); + } + that--; + } + } + return res; + } + } + + @Specialization + double doDouble(long _this, double that) { + return Math.pow(_this, that); + } + + @Specialization + Object doBigInteger(long _this, EnsoBigInteger that) { + return bigIntPowNode.execute(new EnsoBigInteger(BigInteger.valueOf(_this)), that); + } + + @Fallback + Object doOther(long _this, Object that) { + throw new TypeError("Unexpected type provided for argument `that` in Integer.^", this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/SubtractNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/SubtractNode.java index 51fd90c303..d0f13fa913 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/SubtractNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/SubtractNode.java @@ -9,7 +9,7 @@ import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNod import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.number.EnsoBigInteger; -@BuiltinMethod(type = "Int_64", name = "-", description = "Subtraction of numbers.") +@BuiltinMethod(type = "Small_Integer", name = "-", description = "Subtraction of numbers.") public abstract class SubtractNode extends Node { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); @@ -29,6 +29,11 @@ public abstract class SubtractNode extends Node { return toEnsoNumberNode.execute(BigIntegerOps.subtract(_this, that)); } + @Specialization + double doDouble(long _this, double that) { + return _this - that; + } + @Specialization Object doBigInteger(long _this, EnsoBigInteger that) { return toEnsoNumberNode.execute(BigIntegerOps.subtract(_this, that.getValue())); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/ToDecimalNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/ToDecimalNode.java new file mode 100644 index 0000000000..89a53a06a5 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/int64/ToDecimalNode.java @@ -0,0 +1,14 @@ +package org.enso.interpreter.node.expression.builtin.number.int64; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.dsl.BuiltinMethod; + +@BuiltinMethod( + type = "Small_Int", + name = "to_decimal", + description = "Conversion of integers to decimals.") +public class ToDecimalNode extends Node { + double execute(long _this) { + return _this; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/utils/BigIntegerOps.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/utils/BigIntegerOps.java index 5bb09b943c..6efedf1d92 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/utils/BigIntegerOps.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/utils/BigIntegerOps.java @@ -86,8 +86,43 @@ public class BigIntegerOps { return BigInteger.valueOf(a).negate(); } + @CompilerDirectives.TruffleBoundary + public static BigInteger abs(BigInteger a) { + return a.abs(); + } + + @CompilerDirectives.TruffleBoundary + public static BigInteger abs(long a) { + return BigInteger.valueOf(a).abs(); + } + @CompilerDirectives.TruffleBoundary public static boolean equals(BigInteger a, BigInteger b) { return a.equals(b); } + + @CompilerDirectives.TruffleBoundary + public static double toDouble(BigInteger a) { + return a.doubleValue(); + } + + @CompilerDirectives.TruffleBoundary + public static int compare(BigInteger a, BigInteger b) { + return a.compareTo(b); + } + + @CompilerDirectives.TruffleBoundary + public static BigInteger pow(BigInteger a, long b) { + BigInteger res = BigInteger.valueOf(1); + while (b > 0) { + if (b % 2 == 0) { + a = a.pow(2); + b /= 2; + } else { + res = res.multiply(a); + b--; + } + } + return res; + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/literal/DecimalLiteralNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/literal/DecimalLiteralNode.java new file mode 100644 index 0000000000..adddd982e1 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/literal/DecimalLiteralNode.java @@ -0,0 +1,36 @@ +package org.enso.interpreter.node.expression.literal; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.NodeInfo; +import org.enso.interpreter.node.ExpressionNode; + +/** A representation of decimal literals in Enso. */ +@NodeInfo(description = "A decimal literal.") +public final class DecimalLiteralNode extends ExpressionNode { + private final double value; + + private DecimalLiteralNode(double value) { + this.value = value; + } + + /** + * Creates an instance of this node. + * + * @param value the value for the node to represent + * @return a node representing the literal given by {@code value} + */ + public static DecimalLiteralNode build(double value) { + return new DecimalLiteralNode(value); + } + + /** + * Gets the value of the literal. + * + * @param frame the stack frame for execution + * @return the value of the integer literal + */ + @Override + public Object executeGeneric(VirtualFrame frame) { + return this.value; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Number.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Number.java index f316c06aa9..07709be05f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Number.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/builtin/Number.java @@ -10,6 +10,7 @@ public class Number { private final AtomConstructor bigInteger; private final AtomConstructor integer; private final AtomConstructor number; + private final AtomConstructor decimal; /** * Creates and registers number builtins. @@ -22,14 +23,17 @@ public class Number { smallInteger = new AtomConstructor("Small_Integer", scope).initializeFields(); integer = new AtomConstructor("Integer", scope).initializeFields(); bigInteger = new AtomConstructor("Big_Integer", scope).initializeFields(); + decimal = new AtomConstructor("Decimal", scope).initializeFields(); registerInt64Methods(language, scope); registerBigIntegerMethods(language, scope); + registerDecimalMethods(language, scope); scope.registerConstructor(number); scope.registerConstructor(smallInteger); scope.registerConstructor(integer); scope.registerConstructor(bigInteger); + scope.registerConstructor(decimal); } private void registerInt64Methods(Language language, ModuleScope scope) { @@ -48,11 +52,21 @@ public class Number { "*", org.enso.interpreter.node.expression.builtin.number.int64.MultiplyMethodGen.makeFunction( language)); + scope.registerMethod( + smallInteger, + "^", + org.enso.interpreter.node.expression.builtin.number.int64.PowMethodGen.makeFunction( + language)); scope.registerMethod( smallInteger, "/", org.enso.interpreter.node.expression.builtin.number.int64.DivideMethodGen.makeFunction( language)); + scope.registerMethod( + smallInteger, + "div", + org.enso.interpreter.node.expression.builtin.number.int64.DivMethodGen.makeFunction( + language)); scope.registerMethod( smallInteger, "%", @@ -63,11 +77,41 @@ public class Number { "negate", org.enso.interpreter.node.expression.builtin.number.int64.NegateMethodGen.makeFunction( language)); + scope.registerMethod( + smallInteger, + "abs", + org.enso.interpreter.node.expression.builtin.number.int64.AbsMethodGen.makeFunction( + language)); scope.registerMethod( smallInteger, "==", org.enso.interpreter.node.expression.builtin.number.int64.EqualsMethodGen.makeFunction( language)); + scope.registerMethod( + smallInteger, + ">", + org.enso.interpreter.node.expression.builtin.number.int64.GreaterMethodGen.makeFunction( + language)); + scope.registerMethod( + smallInteger, + ">=", + org.enso.interpreter.node.expression.builtin.number.int64.GreaterOrEqualMethodGen + .makeFunction(language)); + scope.registerMethod( + smallInteger, + "<", + org.enso.interpreter.node.expression.builtin.number.int64.LessMethodGen.makeFunction( + language)); + scope.registerMethod( + smallInteger, + "<=", + org.enso.interpreter.node.expression.builtin.number.int64.LessOrEqualMethodGen.makeFunction( + language)); + scope.registerMethod( + smallInteger, + "to_decimal", + org.enso.interpreter.node.expression.builtin.number.int64.ToDecimalMethodGen.makeFunction( + language)); } private void registerBigIntegerMethods(Language language, ModuleScope scope) { @@ -87,11 +131,21 @@ public class Number { "*", org.enso.interpreter.node.expression.builtin.number.bigInteger.MultiplyMethodGen .makeFunction(language)); + scope.registerMethod( + bigInteger, + "^", + org.enso.interpreter.node.expression.builtin.number.bigInteger.PowMethodGen.makeFunction( + language)); scope.registerMethod( bigInteger, "/", org.enso.interpreter.node.expression.builtin.number.bigInteger.DivideMethodGen.makeFunction( language)); + scope.registerMethod( + bigInteger, + "div", + org.enso.interpreter.node.expression.builtin.number.bigInteger.DivMethodGen.makeFunction( + language)); scope.registerMethod( bigInteger, "%", @@ -102,11 +156,110 @@ public class Number { "negate", org.enso.interpreter.node.expression.builtin.number.bigInteger.NegateMethodGen.makeFunction( language)); + scope.registerMethod( + bigInteger, + "abs", + org.enso.interpreter.node.expression.builtin.number.bigInteger.AbsMethodGen.makeFunction( + language)); scope.registerMethod( bigInteger, "==", org.enso.interpreter.node.expression.builtin.number.bigInteger.EqualsMethodGen.makeFunction( language)); + scope.registerMethod( + bigInteger, + ">", + org.enso.interpreter.node.expression.builtin.number.bigInteger.GreaterMethodGen + .makeFunction(language)); + scope.registerMethod( + bigInteger, + ">=", + org.enso.interpreter.node.expression.builtin.number.bigInteger.GreaterOrEqualMethodGen + .makeFunction(language)); + scope.registerMethod( + bigInteger, + "<", + org.enso.interpreter.node.expression.builtin.number.bigInteger.LessMethodGen.makeFunction( + language)); + scope.registerMethod( + bigInteger, + "<=", + org.enso.interpreter.node.expression.builtin.number.bigInteger.LessOrEqualMethodGen + .makeFunction(language)); + scope.registerMethod( + bigInteger, + "to_decimal", + org.enso.interpreter.node.expression.builtin.number.bigInteger.ToDecimalMethodGen + .makeFunction(language)); + } + + private void registerDecimalMethods(Language language, ModuleScope scope) { + + scope.registerMethod( + decimal, + "+", + org.enso.interpreter.node.expression.builtin.number.decimal.AddMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + "-", + org.enso.interpreter.node.expression.builtin.number.decimal.SubtractMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + "*", + org.enso.interpreter.node.expression.builtin.number.decimal.MultiplyMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + "^", + org.enso.interpreter.node.expression.builtin.number.decimal.PowMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + "/", + org.enso.interpreter.node.expression.builtin.number.decimal.DivideMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + "negate", + org.enso.interpreter.node.expression.builtin.number.decimal.NegateMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + "abs", + org.enso.interpreter.node.expression.builtin.number.decimal.AbsMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + "==", + org.enso.interpreter.node.expression.builtin.number.decimal.EqualsMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + ">", + org.enso.interpreter.node.expression.builtin.number.decimal.GreaterMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + ">=", + org.enso.interpreter.node.expression.builtin.number.decimal.GreaterOrEqualMethodGen + .makeFunction(language)); + scope.registerMethod( + decimal, + "<", + org.enso.interpreter.node.expression.builtin.number.decimal.LessMethodGen.makeFunction( + language)); + scope.registerMethod( + decimal, + "<=", + org.enso.interpreter.node.expression.builtin.number.decimal.LessOrEqualMethodGen + .makeFunction(language)); + scope.registerMethod( + decimal, + "to_decimal", + org.enso.interpreter.node.expression.builtin.number.decimal.ToDecimalMethodGen.makeFunction( + language)); } /** @return the Int64 atom constructor. */ @@ -128,4 +281,9 @@ public class Number { public AtomConstructor getNumber() { return number; } + + /** @return the Decimal atom constructor */ + public AtomConstructor getDecimal() { + return decimal; + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java index d9709807f9..90163155a8 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java @@ -1,5 +1,7 @@ package org.enso.interpreter.runtime.number; +import com.oracle.truffle.api.CompilerDirectives; + import java.math.BigInteger; /** Internal wrapper for a {@link BigInteger}. */ @@ -19,4 +21,10 @@ public class EnsoBigInteger { public BigInteger getValue() { return value; } + + @Override + @CompilerDirectives.TruffleBoundary + public String toString() { + return value.toString(); + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java index 69347788d7..9c2f058704 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java @@ -27,6 +27,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @TypeSystem({ long.class, boolean.class, + double.class, String.class, Function.class, Atom.class, diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/AstToIr.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/AstToIr.scala index 63c21e046b..1d991033be 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/AstToIr.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/AstToIr.scala @@ -377,6 +377,8 @@ object AstToIr { allBranches, getIdentifiedLocation(inputAst) ) + case AstView.DecimalLiteral(intPart, fracPart) => + translateDecimalLiteral(inputAst, intPart, fracPart) case AST.App.any(inputAST) => translateApplicationLike(inputAST) case AST.Mixfix.any(inputAST) => translateApplicationLike(inputAST) case AST.Literal.any(inputAST) => translateLiteral(inputAST) @@ -421,6 +423,26 @@ object AstToIr { * argument and cannot be performed any other way. */ + def translateDecimalLiteral( + ast: AST, + int: AST.Literal.Number, + frac: AST.Literal.Number + ): Expression = { + if (int.base.isDefined && int.base.get != "10") { + Error.Syntax( + int, + Error.Syntax.UnsupportedSyntax("non-base-10 number literals") + ) + } else if (frac.base.isDefined && frac.base.get != "10") { + Error.Syntax(frac, Error.Syntax.InvalidBaseInDecimalLiteral) + } else { + Literal.Number( + s"${int.shape.int}.${frac.shape.int}", + getIdentifiedLocation(ast) + ) + } + } + /** Translates a program literal from its [[AST]] representation into * [[IR]]. * diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/AstView.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/AstView.scala index cd14a85cbe..12e63fc018 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/AstView.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/AstView.scala @@ -842,6 +842,19 @@ object AstView { } } + object DecimalLiteral { + def unapply(ast: AST): Option[(AST.Literal.Number, AST.Literal.Number)] = + ast match { + case AST.App.Infix( + AST.Literal.Number.any(int), + AST.Ident.Opr("."), + AST.Literal.Number.any(frac) + ) => + Some((int, frac)) + case _ => None + } + } + object UnaryMinus { def minusSymbol: String = "-" diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala index f4a8edd3c5..28e56593cc 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala @@ -44,6 +44,7 @@ import org.enso.interpreter.node.expression.constant.{ } import org.enso.interpreter.node.expression.literal.{ BigIntegerLiteralNode, + DecimalLiteralNode, IntegerLiteralNode, TextLiteralNode } @@ -859,10 +860,14 @@ class IrToTruffle( */ def processLiteral(literal: IR.Literal): RuntimeExpression = literal match { - case IR.Literal.Number(value, location, _, _) => - val node = value.toLongOption - .map(IntegerLiteralNode.build) - .getOrElse(BigIntegerLiteralNode.build(new BigInteger(value))) + case lit @ IR.Literal.Number(value, location, _, _) => + val node = if (lit.isFractional) { + DecimalLiteralNode.build(value.toDouble) + } else { + value.toLongOption + .map(IntegerLiteralNode.build) + .getOrElse(BigIntegerLiteralNode.build(new BigInteger(value))) + } setLocation(node, location) case IR.Literal.Text(text, location, _, _) => setLocation(TextLiteralNode.build(text), location) diff --git a/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala b/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala index fde6e5ff73..e19db02a66 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala @@ -1581,6 +1581,13 @@ object IR { override def children: List[IR] = List() override def showCode(indent: Int): String = value + + /** + * Checks whether the literal represents a fractional value. + * + * @return `true` if the value is fractional, `false` otherwise. + */ + def isFractional: Boolean = value.contains(".") } /** A textual Enso literal. @@ -5563,6 +5570,11 @@ object IR { def explanation: String } + case object InvalidBaseInDecimalLiteral extends Reason { + override def explanation: String = + "Cannot change base of the fractional part of a number literal." + } + case class UnsupportedSyntax(syntaxName: String) extends Reason { override def explanation: String = s"Syntax is not supported yet: $syntaxName." diff --git a/test/Benchmarks/src/Collections.enso b/test/Benchmarks/src/Collections.enso index 3c14eb9e48..11c85f2968 100644 --- a/test/Benchmarks/src/Collections.enso +++ b/test/Benchmarks/src/Collections.enso @@ -15,5 +15,7 @@ main = mil = 1000000 list = here.gen_list mil vec = Vector.new mil (ix -> ix + 1) + vec_decimal = Vector.new mil (ix -> ix + 0.0) Bench_Utils.measure (vec.fold 0 (+)) "vector fold" 1000 10 Bench_Utils.measure (list.fold 0 (+)) "list fold" 1000 10 + Bench_Utils.measure (vec_decimal.fold 0 (+)) "vector decimal fold" 1000 10 diff --git a/test/Benchmarks/src/Main.enso b/test/Benchmarks/src/Main.enso index a6afbbb250..4081126760 100644 --- a/test/Benchmarks/src/Main.enso +++ b/test/Benchmarks/src/Main.enso @@ -12,6 +12,14 @@ sum_tco = sum_to -> res = summator 0 sum_to res +sum_tco_decimal = sum_to -> + s = sum_to.to_decimal + summator = acc -> current -> + if current >= s then acc else summator acc+current current+1.0 + res = summator 0.0 0.0 + res + + sum_tco_java = sum_to -> summator = acc -> current -> if current == 0 then acc else summator (Long.sum [acc, current]) (current - 1) @@ -40,8 +48,10 @@ sum_state = sum_to -> main = hundred_mil = 100000000 + IO.println "Measuring Sum TCO Decimal" + Bench_Utils.measure (here.sum_tco_decimal hundred_mil) "sum_tco" 100 10 IO.println "Measuring SumTCO" - Bench_Utils.measure (here.sum_tco hundred_mil) "sum_tco" 500 10 + Bench_Utils.measure (here.sum_tco hundred_mil) "sum_tco" 100 10 IO.println "Measuring SumTCO Java" Bench_Utils.measure (here.sum_tco_java hundred_mil) "sum_tco" 100 10 IO.println "Measuring State" diff --git a/test/Test/src/Java_Interop/Spec.enso b/test/Test/src/Java_Interop/Spec.enso index 8d67485933..ee8ee2d6ca 100644 --- a/test/Test/src/Java_Interop/Spec.enso +++ b/test/Test/src/Java_Interop/Spec.enso @@ -2,7 +2,13 @@ from Base import all import Base.Test polyglot java import java.lang.Long +polyglot java import java.lang.Integer +polyglot java import java.lang.Float spec = describe "Java FFI" <| it "should call methods imported from Java" <| Long.sum [1, 2] . should_equal 3 + it "should auto-convert numeric types across the polyglot boundary" <| + (Float.valueOf ["123.3"] + 5).should_equal 128.3 epsilon=0.0001 + (Integer.sum [1, 2] + 3) . should_equal 6 + diff --git a/test/Test/src/Numbers/Spec.enso b/test/Test/src/Numbers/Spec.enso index 97e3b3dfe2..5ffdf03cdf 100644 --- a/test/Test/src/Numbers/Spec.enso +++ b/test/Test/src/Numbers/Spec.enso @@ -3,8 +3,10 @@ from Base import all import Base.Test Integer.is_even = this % 2 == 0 +Decimal.get_fun_factor = "Wow, " + this.to_text + " is such a fun number!" spec = + eps = 0.000001 almost_max_long = 9223372036854775806 almost_max_long_times_three = 27670116110564327418 hundred_factorial = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 @@ -17,7 +19,7 @@ spec = (0 - almost_max_long - almost_max_long - almost_max_long).should_equal almost_max_long_times_three.negate it "should be of unbound size when dividing" <| expected = 3372816184472482867110284450043137767873196479305249187406461598235841786750685581361224832688174410089430537516012695688121622150430744676 - ((1.upto 101 . fold 1 (*)) / 3*almost_max_long).should_equal expected + ((1.upto 101 . fold 1 (*)).div 3*almost_max_long).should_equal expected it "should be of unbound size when taking remainder" <| expected = 3191479909175673432 ((1.upto 101 . fold 1 (*)) % 3*almost_max_long).should_equal expected @@ -34,4 +36,33 @@ spec = (hundred_factorial == 1).should_be_false it "should properly handle going to big numbers and back" <| ((almost_max_long * 3) / 3) . should_equal almost_max_long - + it "should use floating point arithmetic for division" <| + (3 / 4) . should_equal 0.75 epsilon=eps + (almost_max_long * 2 / almost_max_long_times_three) . should_equal 0.6666666 epsilon=eps + describe "Decimals" <| + it "should exist and expose basic arithmetic operations" <| + ((1.5 + 1.5)*1.3 / 2 - 3) . should_equal -1.05 epsilon=eps + it "should allow defining extension methods through the Decimal type" <| + 32.5.get_fun_factor.should_equal "Wow, 32.5 is such a fun number!" + describe "Numbers" <| + it "should expose comparison operators" <| + (3 < hundred_factorial).should_be_true + (hundred_factorial < 3).should_be_false + (3.0 < hundred_factorial).should_be_true + (3.0 <= 3.4).should_be_true + (3.0 >= 2).should_be_true + (-hundred_factorial > 0).should_be_false + it "should expose exponentiation operations" <| + (3.14 ^ 2.71).should_equal 22.216689546 epsilon=eps + (3.14 ^ 14).should_equal 9057640.36635 epsilon=eps + a = almost_max_long + (a ^ 4).should_equal (a * a * a * a) + (2 ^ 10).should_equal 1024 + (2 ^ 0.5).should_equal 1.41421356237 epsilon=eps + (a^2)^0.5 . should_equal a epsilon=eps + it "should expose more involved mathematical functions" <| + Math.Pi.sin.should_equal 0 epsilon=eps + (Math.Pi / 4).sin.should_equal (2 ^ 0.5)/2 epsilon=eps + (Math.Pi / 6).cos.should_equal (3.sqrt / 2) epsilon=eps + (17 ^ 0.13).log base=17 . should_equal 0.13 epsilon=eps + 0.exp.should_equal 1