Decimal Numbers (#1146)

This commit is contained in:
Marcin Kostrzewa 2020-09-15 15:05:21 +02:00 committed by GitHub
parent 9666d9065e
commit e38d1ab521
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 1682 additions and 51 deletions

View File

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

View File

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

View File

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

View File

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

66
docs/semantics/numbers.md Normal file
View File

@ -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.
<!-- MarkdownTOC levels="2,3" autolink="true" -->
- [Number Types](#number-types)
- [Internal Representation](#internal-representation)
- [Type Conversions](#type-conversions)
<!-- /MarkdownTOC -->
## 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.

View File

@ -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();

View File

@ -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;
}
}

View File

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

View File

@ -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()));
}
}

View File

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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

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

View File

@ -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);
}
}

View File

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

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

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

View File

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

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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()));

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -27,6 +27,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
@TypeSystem({
long.class,
boolean.class,
double.class,
String.class,
Function.class,
Atom.class,

View File

@ -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]].
*

View File

@ -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 = "-"

View File

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

View File

@ -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."

View File

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

View File

@ -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"

View File

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

View File

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