diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9ec9b7eb6be..5f2684d9c43 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -68,10 +68,12 @@
- [Support for creating Atoms in expressions.][10820]
- [IO.print without new line][10858]
- [Add `Text.to_decimal`.][10874]
-- [Added .floor, .ceil, .trunc to the in-memory `Decimal` column.][10887]
+- [Added `floor`, `ceil`, `trunc` to the in-memory `Decimal` column.][10887]
- [Added vectorized .round to the in-memory `Decimal` column.][10912]
- [`select_into_database_table` no longer defaults the primary key to the first
column.][11120]
+- [Extend the range of `floor`, `ceil`, `trunc` to values outside the `Long`
+ range.][11135]
- [Added `format` parameter to `Decimal.parse`.][11205]
[10614]: https://github.com/enso-org/enso/pull/10614
@@ -85,6 +87,7 @@
[10887]: https://github.com/enso-org/enso/pull/10887
[10912]: https://github.com/enso-org/enso/pull/10912
[11120]: https://github.com/enso-org/enso/pull/11120
+[11135]: https://github.com/enso-org/enso/pull/11135
[11205]: https://github.com/enso-org/enso/pull/11205
#### Enso Language & Runtime
diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso
index 42e3c9bb9cd..88138269b92 100644
--- a/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso
+++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso
@@ -46,7 +46,6 @@ polyglot java import org.enso.table.data.column.operation.unary.IsNothingOperati
polyglot java import org.enso.table.data.column.operation.unary.NotOperation
polyglot java import org.enso.table.data.column.operation.unary.TextLengthOperation
polyglot java import org.enso.table.data.column.operation.unary.TruncatedTimePartOperation
-polyglot java import org.enso.table.data.column.operation.unary.UnaryDecimalRoundOperation
polyglot java import org.enso.table.data.column.operation.unary.UnaryRoundOperation
polyglot java import org.enso.table.data.column.operation.UnaryOperation
polyglot java import org.enso.table.data.column.storage.Storage as Java_Storage
@@ -930,11 +929,8 @@ type Column
case precise_value_type.is_integer of
True ->
self.rename new_name
- False -> case precise_value_type.is_decimal of
- True ->
- apply_unary_operation self UnaryDecimalRoundOperation.TRUNCATE_INSTANCE
- False ->
- apply_unary_operation self UnaryRoundOperation.TRUNCATE_INSTANCE
+ False ->
+ apply_unary_operation self UnaryRoundOperation.TRUNCATE_INSTANCE
False -> case precise_value_type == Value_Type.Date_Time of
True ->
fun = _.date
@@ -959,11 +955,7 @@ type Column
new_name = naming_helper.function_name "ceil" [self]
self.rename new_name
False ->
- case self.inferred_precise_value_type.is_decimal of
- True ->
- apply_unary_operation self UnaryDecimalRoundOperation.CEIL_INSTANCE
- False ->
- apply_unary_operation self UnaryRoundOperation.CEIL_INSTANCE
+ apply_unary_operation self UnaryRoundOperation.CEIL_INSTANCE
## GROUP Standard.Base.Rounding
ICON math
@@ -983,11 +975,7 @@ type Column
new_name = naming_helper.function_name "floor" [self]
self.rename new_name
False ->
- case self.inferred_precise_value_type.is_decimal of
- True ->
- apply_unary_operation self UnaryDecimalRoundOperation.FLOOR_INSTANCE
- False ->
- apply_unary_operation self UnaryRoundOperation.FLOOR_INSTANCE
+ apply_unary_operation self UnaryRoundOperation.FLOOR_INSTANCE
## GROUP Standard.Base.Logical
ICON operators
diff --git a/distribution/lib/Standard/Test/0.0.0-dev/src/Faker.enso b/distribution/lib/Standard/Test/0.0.0-dev/src/Faker.enso
index 75abb8d7a84..c033d79ddfd 100644
--- a/distribution/lib/Standard/Test/0.0.0-dev/src/Faker.enso
+++ b/distribution/lib/Standard/Test/0.0.0-dev/src/Faker.enso
@@ -1,5 +1,6 @@
from Standard.Base import all
+polyglot java import java.math.BigInteger
polyglot java import java.util.Random as Java_Random
polyglot java import org.enso.base.Text_Utils
@@ -112,6 +113,38 @@ type Faker
integer self minimum=0 maximum=100 =
minimum + (self.generator.nextInt (maximum - minimum))
+ ## GROUP Standard.Base.Random
+ ICON random
+ Create a random large Integer value (represented internally as a Java
+ `BigInteger`.
+
+ The values provided by this method are selected from a sparse set within
+ the specified range. For example, with `bit_length=4`, the possible range
+ is -16 to 16, but the actual values only include 9, 11, 13 and 15.
+
+ Arguments
+ - bit_length: specifies the range of values to select from. The values
+ will be between -2^bit_length and 2^bit_length.
+ large_integer : Integer -> Integer -> Integer
+ large_integer self bit_length =
+ BigInteger.new bit_length 0 self.generator
+
+ ## GROUP Standard.Base.Random
+ ICON random
+ Create a random Decimal value (represented internally as a Java
+ `BigDecimal`.
+
+ This generator uses `large_integer` to generate an `Integer`, and then
+ adds a random `Float`. See `large_integer` for a description of the range
+ of values that this can return.
+
+ Arguments
+ - bit_length: specifies the range of values to select from. The values
+ will be between -2^bit_length and 2^bit_length.
+ decimal : Integer -> Integer -> Integer
+ decimal self bit_length =
+ (self.large_integer bit_length) + self.float
+
## GROUP Standard.Base.Random
ICON random
Create a random Float value
diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/builder/InferredIntegerBuilder.java b/std-bits/table/src/main/java/org/enso/table/data/column/builder/InferredIntegerBuilder.java
new file mode 100644
index 00000000000..f89a6bf3897
--- /dev/null
+++ b/std-bits/table/src/main/java/org/enso/table/data/column/builder/InferredIntegerBuilder.java
@@ -0,0 +1,132 @@
+package org.enso.table.data.column.builder;
+
+import java.math.BigInteger;
+import org.enso.base.polyglot.NumericConverter;
+import org.enso.table.data.column.storage.Storage;
+import org.enso.table.data.column.storage.type.BigIntegerType;
+import org.enso.table.data.column.storage.type.IntegerType;
+import org.enso.table.data.column.storage.type.StorageType;
+import org.enso.table.problems.ProblemAggregator;
+
+/**
+ * A builder for storing enso Integers, which might be Longs or BigIntegers.
+ *
+ *
This builder starts off delegating to LongBuilder, but if it receives a BigInteger, it retypes
+ * the LongBuilder to a BigIntegerBuilder.
+ */
+public class InferredIntegerBuilder extends Builder {
+ private LongBuilder longBuilder = null;
+ private TypedBuilder bigIntegerBuilder = null;
+ private int currentSize = 0;
+ private final int initialSize;
+ private final ProblemAggregator problemAggregator;
+
+ /** Creates a new instance of this builder, with the given known result length. */
+ public InferredIntegerBuilder(int initialSize, ProblemAggregator problemAggregator) {
+ this.initialSize = initialSize;
+ this.problemAggregator = problemAggregator;
+
+ longBuilder =
+ NumericBuilder.createLongBuilder(this.initialSize, IntegerType.INT_64, problemAggregator);
+ }
+
+ @Override
+ public void appendNoGrow(Object o) {
+ if (o == null) {
+ appendNulls(1);
+ } else if (o instanceof BigInteger bi) {
+ retypeToBigIntegerMaybe();
+ bigIntegerBuilder.appendNoGrow(bi);
+ } else {
+ Long lng = NumericConverter.tryConvertingToLong(o);
+ if (lng == null) {
+ throw new IllegalStateException(
+ "Unexpected value added to InferredIntegerBuilder "
+ + o.getClass()
+ + ". This is a bug in the Table library.");
+ } else {
+ if (bigIntegerBuilder != null) {
+ bigIntegerBuilder.appendNoGrow(BigInteger.valueOf(lng));
+ } else {
+ longBuilder.appendNoGrow(lng);
+ }
+ }
+ }
+ currentSize++;
+ }
+
+ @Override
+ public void append(Object o) {
+ if (o == null) {
+ appendNulls(1);
+ } else if (o instanceof BigInteger bi) {
+ retypeToBigIntegerMaybe();
+ bigIntegerBuilder.append(bi);
+ } else {
+ Long lng = NumericConverter.tryConvertingToLong(o);
+ if (lng == null) {
+ throw new IllegalStateException(
+ "Unexpected value added to InferredIntegerBuilder "
+ + o.getClass()
+ + ". This is a bug in the Table library.");
+ } else {
+ if (bigIntegerBuilder != null) {
+ bigIntegerBuilder.append(BigInteger.valueOf(lng));
+ } else {
+ longBuilder.append(lng);
+ }
+ }
+ }
+ currentSize++;
+ }
+
+ @Override
+ public void appendNulls(int count) {
+ if (bigIntegerBuilder != null) {
+ bigIntegerBuilder.appendNulls(count);
+ } else {
+ longBuilder.appendNulls(count);
+ }
+ currentSize += count;
+ }
+
+ @Override
+ public void appendBulkStorage(Storage> storage) {
+ for (int i = 0; i < storage.size(); i++) {
+ append(storage.getItemBoxed(i));
+ }
+ }
+
+ @Override
+ public int getCurrentSize() {
+ return currentSize;
+ }
+
+ @Override
+ public Storage> seal() {
+ if (bigIntegerBuilder != null) {
+ return bigIntegerBuilder.seal();
+ } else {
+ return longBuilder.seal();
+ }
+ }
+
+ @Override
+ public StorageType getType() {
+ if (bigIntegerBuilder != null) {
+ return BigIntegerType.INSTANCE;
+ } else {
+ return IntegerType.INT_64;
+ }
+ }
+
+ // Retype the LongBuilder to a BigIntegerBuilder, if we haven't already
+ // done so.
+ private void retypeToBigIntegerMaybe() {
+ if (bigIntegerBuilder != null) {
+ return;
+ }
+ bigIntegerBuilder = longBuilder.retypeTo(BigIntegerType.INSTANCE);
+ longBuilder = null;
+ }
+}
diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/operation/unary/UnaryDecimalRoundOperation.java b/std-bits/table/src/main/java/org/enso/table/data/column/operation/unary/UnaryDecimalRoundOperation.java
deleted file mode 100644
index 6876311c778..00000000000
--- a/std-bits/table/src/main/java/org/enso/table/data/column/operation/unary/UnaryDecimalRoundOperation.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.enso.table.data.column.operation.unary;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.function.Function;
-import org.enso.base.numeric.Decimal_Utils;
-import org.enso.table.data.column.builder.Builder;
-import org.enso.table.data.column.builder.InferredBuilder;
-import org.enso.table.data.column.operation.UnaryOperation;
-import org.enso.table.data.column.operation.map.MapOperationProblemAggregator;
-import org.enso.table.data.column.storage.ColumnStorage;
-import org.enso.table.data.column.storage.type.BigDecimalType;
-
-public class UnaryDecimalRoundOperation extends AbstractUnaryOperation {
- public static final String CEIL = "ceil";
- public static final UnaryOperation CEIL_INSTANCE =
- new UnaryDecimalRoundOperation(CEIL, Decimal_Utils::ceil);
-
- public static final String FLOOR = "floor";
- public static final UnaryOperation FLOOR_INSTANCE =
- new UnaryDecimalRoundOperation(FLOOR, Decimal_Utils::floor);
-
- public static String TRUNCATE = "truncate";
- public static final UnaryOperation TRUNCATE_INSTANCE =
- new UnaryDecimalRoundOperation(TRUNCATE, Decimal_Utils::truncate);
-
- private final Function function;
-
- private UnaryDecimalRoundOperation(String name, Function function) {
- super(name, true);
- this.function = function;
- }
-
- @Override
- public boolean canApply(ColumnStorage storage) {
- return storage.getType() instanceof BigDecimalType;
- }
-
- @Override
- protected final void applyObjectRow(
- Object value, Builder builder, MapOperationProblemAggregator problemAggregator) {
- applyObjectRow(value, (InferredBuilder) builder, problemAggregator);
- }
-
- protected void applyObjectRow(
- Object value, InferredBuilder builder, MapOperationProblemAggregator problemAggregator) {
- switch (value) {
- case BigDecimal d -> builder.append(function.apply(d));
- default -> throw new IllegalArgumentException(
- "Unsupported type: " + value.getClass() + " (expected decimal).");
- }
- }
-}
diff --git a/std-bits/table/src/main/java/org/enso/table/data/column/operation/unary/UnaryRoundOperation.java b/std-bits/table/src/main/java/org/enso/table/data/column/operation/unary/UnaryRoundOperation.java
index efce629ff08..a7927f9db2b 100644
--- a/std-bits/table/src/main/java/org/enso/table/data/column/operation/unary/UnaryRoundOperation.java
+++ b/std-bits/table/src/main/java/org/enso/table/data/column/operation/unary/UnaryRoundOperation.java
@@ -1,31 +1,58 @@
package org.enso.table.data.column.operation.unary;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.function.DoubleToLongFunction;
-import org.enso.table.data.column.builder.LongBuilder;
+import java.util.function.Function;
+import org.enso.base.numeric.Decimal_Utils;
+import org.enso.table.data.column.builder.Builder;
+import org.enso.table.data.column.builder.InferredIntegerBuilder;
import org.enso.table.data.column.operation.UnaryOperation;
import org.enso.table.data.column.operation.map.MapOperationProblemAggregator;
import org.enso.table.data.column.storage.ColumnLongStorage;
import org.enso.table.data.column.storage.ColumnStorage;
-import org.enso.table.data.column.storage.type.IntegerType;
+import org.enso.table.data.column.storage.numeric.BigIntegerStorage;
+
+public class UnaryRoundOperation extends AbstractUnaryOperation {
+ // Used to determine whether we should use Double or BigDecimal operations.
+ // Values outside this range are promoted to BigDecimal operation, because
+ // representing their rounded value as a Long might overflow the Long dynamic
+ // range.
+ public static final double USE_DOUBLE_LIMIT_POSITIVE = 9223372036854775000.0;
+ public static final double USE_DOUBLE_LIMIT_NEGATIVE = -9223372036854775000.0;
-public class UnaryRoundOperation extends AbstractUnaryLongOperation {
public static final String CEIL = "ceil";
public static final UnaryOperation CEIL_INSTANCE =
- new UnaryRoundOperation(CEIL, d -> (long) Math.ceil(d));
+ new UnaryRoundOperation(CEIL, d -> (long) Math.ceil(d), Decimal_Utils::ceil);
public static final String FLOOR = "floor";
public static final UnaryOperation FLOOR_INSTANCE =
- new UnaryRoundOperation(FLOOR, d -> (long) Math.floor(d));
+ new UnaryRoundOperation(FLOOR, d -> (long) Math.floor(d), Decimal_Utils::floor);
public static String TRUNCATE = "truncate";
public static final UnaryOperation TRUNCATE_INSTANCE =
- new UnaryRoundOperation(TRUNCATE, d -> (long) d);
+ new UnaryRoundOperation(TRUNCATE, d -> (long) d, Decimal_Utils::truncate);
- private final DoubleToLongFunction function;
+ private final DoubleToLongFunction doubleFunction;
+ private final Function bigDecimalFunction;
- private UnaryRoundOperation(String name, DoubleToLongFunction function) {
- super(name, true, IntegerType.INT_64);
- this.function = function;
+ private UnaryRoundOperation(
+ String name,
+ DoubleToLongFunction doubleFunction,
+ Function bigDecimalFunction) {
+ super(name, true);
+ this.doubleFunction = doubleFunction;
+ this.bigDecimalFunction = bigDecimalFunction;
+ }
+
+ protected Builder createBuilder(
+ ColumnStorage storage, MapOperationProblemAggregator problemAggregator) {
+ if (storage.getSize() > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException(
+ "Cannot currently operate on columns larger than " + Integer.MAX_VALUE + ".");
+ }
+
+ return new InferredIntegerBuilder((int) storage.getSize(), problemAggregator);
}
@Override
@@ -36,9 +63,9 @@ public class UnaryRoundOperation extends AbstractUnaryLongOperation {
@Override
public ColumnStorage apply(
ColumnStorage storage, MapOperationProblemAggregator problemAggregator) {
- if (storage instanceof ColumnLongStorage longStorage) {
- // For a long storage, the operation is an identity operation.
- return longStorage;
+ if (storage instanceof ColumnLongStorage || storage instanceof BigIntegerStorage) {
+ // For an integral type storage, the operation is an identity operation.
+ return storage;
}
return super.apply(storage, problemAggregator);
@@ -46,7 +73,7 @@ public class UnaryRoundOperation extends AbstractUnaryLongOperation {
@Override
protected void applyObjectRow(
- Object value, LongBuilder builder, MapOperationProblemAggregator problemAggregator) {
+ Object value, Builder builder, MapOperationProblemAggregator problemAggregator) {
// Null handled by base class
switch (value) {
case Double d -> {
@@ -54,11 +81,16 @@ public class UnaryRoundOperation extends AbstractUnaryLongOperation {
String msg = "Value is " + d;
problemAggregator.reportArithmeticError(msg, builder.getCurrentSize());
builder.appendNulls(1);
+ } else if (d > USE_DOUBLE_LIMIT_POSITIVE || d < USE_DOUBLE_LIMIT_NEGATIVE) {
+ builder.append(bigDecimalFunction.apply(BigDecimal.valueOf(d)));
} else {
- builder.appendLong(function.applyAsLong(d));
+ builder.append(doubleFunction.applyAsLong(d));
}
}
case Float f -> applyObjectRow((double) f, builder, problemAggregator);
+ case BigDecimal bd -> {
+ builder.append(bigDecimalFunction.apply(bd));
+ }
case Number n -> applyObjectRow(n.doubleValue(), builder, problemAggregator);
default -> throw new IllegalArgumentException(
"Unsupported type: " + value.getClass() + " (expected numeric type).");
diff --git a/test/Benchmarks/src/Column_Numeric.enso b/test/Benchmarks/src/Column_Numeric.enso
index 8ee25a57df6..756b451d511 100644
--- a/test/Benchmarks/src/Column_Numeric.enso
+++ b/test/Benchmarks/src/Column_Numeric.enso
@@ -8,10 +8,10 @@ options = Bench.options
type Data
- Value ~ints ~floats
+ Value ~ints ~floats ~large_ints ~large_floats ~decimals
create vector_size faker =
- Data.Value (create_ints vector_size faker) (create_floats vector_size faker)
+ Data.Value (create_ints vector_size faker) (create_floats vector_size faker) (create_large_ints vector_size faker) (create_large_floats vector_size faker) (create_decimals vector_size faker)
create_ints vector_size faker =
@@ -24,6 +24,21 @@ create_floats vector_size faker =
Column.from_vector "floats" floats_vec
+create_large_ints vector_size faker =
+ ints_vec = Vector.new vector_size _->(faker.large_integer 60)
+ Column.from_vector "large_ints" ints_vec
+
+
+create_large_floats vector_size faker =
+ floats_vec = Vector.new vector_size _->(faker.float -1000000000000000000000.0 1000000000000000000000.0)
+ Column.from_vector "large_floats" floats_vec
+
+
+create_decimals vector_size faker =
+ decimals_vec = Vector.new vector_size _->(faker.decimal 60)
+ Column.from_vector "decimals" decimals_vec
+
+
collect_benches = Bench.build builder->
vector_size = 5 * 1000 * 1000
## No specific significance to this constant, just fixed to make generated set deterministic
@@ -33,18 +48,6 @@ collect_benches = Bench.build builder->
data = Data.create vector_size faker
builder.group "Column_Numeric" options group_builder->
- group_builder.specify "round_floats" <|
- data.floats.round
-
- group_builder.specify "truncate_floats" <|
- data.floats.truncate
-
- group_builder.specify "ceil_floats" <|
- data.floats.ceil
-
- group_builder.specify "floor_floats" <|
- data.floats.floor
-
group_builder.specify "round_ints" <|
data.ints.round
@@ -57,16 +60,76 @@ collect_benches = Bench.build builder->
group_builder.specify "floor_ints" <|
data.ints.floor
+ group_builder.specify "round_floats" <|
+ data.floats.round
+
+ group_builder.specify "truncate_floats" <|
+ data.floats.truncate
+
+ group_builder.specify "ceil_floats" <|
+ data.floats.ceil
+
+ group_builder.specify "floor_floats" <|
+ data.floats.floor
+
+ group_builder.specify "round_large_ints" <|
+ data.large_ints.round
+
+ group_builder.specify "truncate_large_ints" <|
+ data.large_ints.truncate
+
+ group_builder.specify "ceil_large_ints" <|
+ data.large_ints.ceil
+
+ group_builder.specify "floor_large_ints" <|
+ data.large_ints.floor
+
+ ## Re-enable when https://github.com/enso-org/enso/issues/11132 is done.
+ group_builder.specify "round_large_floats" <|
+ data.large_floats.round
+
+ group_builder.specify "truncate_large_floats" <|
+ data.large_floats.truncate
+
+ group_builder.specify "ceil_large_floats" <|
+ data.large_floats.ceil
+
+ group_builder.specify "floor_large_floats" <|
+ data.large_floats.floor
+
+ ## Re-enable when https://github.com/enso-org/enso/issues/11132 is done.
+ group_builder.specify "round_decimals" <|
+ data.decimals.round
+
+ group_builder.specify "truncate_decimals" <|
+ data.decimals.truncate
+
+ group_builder.specify "ceil_decimals" <|
+ data.decimals.ceil
+
+ group_builder.specify "floor_decimals" <|
+ data.decimals.floor
+
[True, False].each use_bankers->
[0, -2, 2].map decimal_places->
name = create_name "round_decimal_places_" decimal_places use_bankers
fun x = x.round decimal_places use_bankers
+ group_builder.specify ("ints_" + name) <|
+ fun data.ints
+
group_builder.specify ("floats_" + name) <|
fun data.floats
- group_builder.specify ("ints_" + name) <|
- fun data.ints
+ ## Re-enable when https://github.com/enso-org/enso/issues/11132 is done.
+ group_builder.specify ("large_ints_" + name) <|
+ fun data.large_ints
+
+ group_builder.specify ("large_floats_" + name) <|
+ fun data.large_floats
+
+ group_builder.specify ("decimals_" + name) <|
+ fun data.decimals
## Creates a valid name for the benchmark
diff --git a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso
index 6f9e3f89d65..d1f1d8b96d5 100644
--- a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso
+++ b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso
@@ -1153,6 +1153,27 @@ add_column_operation_specs suite_builder setup =
table = table_builder [["x", [0, 3, -3, 1, -2]]]
table.at "x" . round 16 . should_fail_with Illegal_Argument
+ if setup.test_selection.supports_decimal_type then
+ group_builder.specify "ceil, floor and truncate should work correctly on Integers outside the java Long range" <|
+ positive_values = [9223372036854775806, 9223372036854775807, 9223372036854775808, 9223372036854775809, 9223372036854775807000000]
+ values = positive_values + positive_values.map .negate
+ values.map x->
+ c = table_builder [["x", [x, -x]]] . at "x"
+ c.ceil . to_vector . should_equal [x, -x]
+ c.floor . to_vector . should_equal [x, -x]
+ c.truncate . to_vector . should_equal [x, -x]
+
+ if setup.is_database.not then
+ group_builder.specify "ceil, floor and truncate should work correctly on Floats outside the java Long range" <|
+ positive_values = [9223372036854775000.0, 9223372036854776000.0, 9223372036854775807000000.0]
+ values = positive_values + positive_values.map .negate
+ values.map x->
+ x_int = x.truncate
+ c = table_builder [["x", [x, -x]]] . at "x"
+ c.ceil . to_vector . should_equal [x_int, -x_int]
+ c.floor . to_vector . should_equal [x_int, -x_int]
+ c.truncate . to_vector . should_equal [x_int, -x_int]
+
if setup.test_selection.supports_decimal_type then
group_builder.specify "ceil, floor and truncate should work correctly on Decimals" <|
c = table_builder [["X", [Decimal.new "123492233720368547758075678.25", Decimal.new "179243023788662739454197523.625", Decimal.new "-123492233720368547758075678.25", Decimal.new "-179243023788662739454197523.625"]]] . at "X"
diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso
index 4b7687bcb9c..f788d10fedc 100644
--- a/test/Table_Tests/src/In_Memory/Column_Spec.enso
+++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso
@@ -370,6 +370,19 @@ add_specs suite_builder =
warnings . should_contain <| Arithmetic_Error.Error 'Value is Infinity (at rows [3]).'
warnings . should_contain <| Arithmetic_Error.Error 'Value is NaN (at rows [2]).'
+ suite_builder.group "InferredIntegerBuilder" group_builder->
+ group_builder.specify "Should be able to handle Nothings" <|
+ c = Column.from_vector "x" [Nothing, 1, Nothing, Nothing, 2, 3, Nothing, Nothing, Nothing, Nothing, 4, 5, Nothing, Nothing, 6, Nothing, 7, Nothing]
+ c.truncate.to_vector . should_equal c.to_vector
+ c.truncate.length . should_equal c.length
+
+ group_builder.specify "Should be able to handle mixed integer / biginteger" <|
+ c0 = Column.from_vector "x" [1, 2, 3, 4, 5, 9223372036854775807001, 9223372036854775807002, 9223372036854775807003, 6, 7, 8]
+ c1 = Column.from_vector "x" [9223372036854775807001, 9223372036854775807002, 1, 2, 3, 4, 5, 9223372036854775807003, 6, 7, 8]
+ [c0, c1].map c->
+ c.truncate.to_vector . should_equal c.to_vector
+ c.truncate.length . should_equal c.length
+
suite_builder.group "Date_Time truncate" group_builder->
group_builder.specify "should be able to truncate a column of Date_Times" <|
c = Column.from_vector "foo" [Date_Time.new 2020 10 24 1 2 3, Date_Time.new 2020 10 24 1 2 3]