Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/


package org.opensearch.sql.expression.operator.arthmetic;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class MathUtil {

/**
* Truncates a double number to required decimal places.
*
* @param numberToTruncate number to be truncated
* @param numberOfDecimals required decimal places
* @return truncated number as double
*/
public static double truncateDouble(double numberToTruncate, int numberOfDecimals) {
return new BigDecimal(String.valueOf(numberToTruncate)).setScale(numberOfDecimals,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it worthwhile to have this class. These are all single-line calls used a single time. I would prefer to remove this file and include the code in the MathematicalFunction.java code.

Like:

            FunctionDSL.nullMissingHandling(
                (x, y) -> new ExprLongValue(
                    new BigDecimal(String.valueOf(numberToTruncate)).setScale(numberOfDecimals, numberToTruncate > 0 ? RoundingMode.FLOOR : RoundingMode.CEILING).doubleValue()),
            LONG, INTEGER, INTEGER),

numberToTruncate > 0 ? RoundingMode.FLOOR : RoundingMode.CEILING).doubleValue();
}

/**
* Truncates a float number to required decimal places.
*
* @param numberToTruncate number to be truncated
* @param numberOfDecimals required decimal places
* @return truncated number as double
*/
public static double truncateFloat(float numberToTruncate, int numberOfDecimals) {
return new BigDecimal(String.valueOf(numberToTruncate)).setScale(numberOfDecimals,
numberToTruncate > 0 ? RoundingMode.FLOOR : RoundingMode.CEILING).doubleValue();
}

/**
* Truncates an int number to required decimal places.
*
* @param numberToTruncate number to be truncated
* @param numberOfDecimals required decimal places
* @return truncated number as long
*/
public static long truncateInt(int numberToTruncate, int numberOfDecimals) {
return new BigDecimal(String.valueOf(numberToTruncate)).setScale(numberOfDecimals,
numberToTruncate > 0 ? RoundingMode.FLOOR : RoundingMode.CEILING).longValue();
}

/**
* Truncates a long number to required decimal places.
*
* @param numberToTruncate number to be truncated
* @param numberOfDecimals required decimal places
* @return truncated number as long
*/
public static long truncateLong(long numberToTruncate, int numberOfDecimals) {
return new BigDecimal(String.valueOf(numberToTruncate)).setScale(numberOfDecimals,
numberToTruncate > 0 ? RoundingMode.FLOOR : RoundingMode.CEILING).longValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -500,26 +500,22 @@ private static DefaultFunctionResolver truncate() {
FunctionDSL.impl(
FunctionDSL.nullMissingHandling(
(x, y) -> new ExprLongValue(
new BigDecimal(x.integerValue()).setScale(y.integerValue(),
RoundingMode.DOWN).longValue())),
MathUtil.truncateInt(x.integerValue(), y.integerValue()))),
LONG, INTEGER, INTEGER),
FunctionDSL.impl(
FunctionDSL.nullMissingHandling(
(x, y) -> new ExprLongValue(
new BigDecimal(x.integerValue()).setScale(y.integerValue(),
RoundingMode.DOWN).longValue())),
MathUtil.truncateLong(x.longValue(), y.integerValue()))),
LONG, LONG, INTEGER),
FunctionDSL.impl(
FunctionDSL.nullMissingHandling(
(x, y) -> new ExprDoubleValue(
new BigDecimal(x.floatValue()).setScale(y.integerValue(),
RoundingMode.DOWN).doubleValue())),
MathUtil.truncateFloat(x.floatValue(), y.integerValue()))),
DOUBLE, FLOAT, INTEGER),
FunctionDSL.impl(
FunctionDSL.nullMissingHandling(
(x, y) -> new ExprDoubleValue(
new BigDecimal(x.doubleValue()).setScale(y.integerValue(),
RoundingMode.DOWN).doubleValue())),
MathUtil.truncateDouble(x.doubleValue(), y.integerValue()))),
DOUBLE, DOUBLE, INTEGER));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.opensearch.sql.expression.operator.arthmetic;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

/**
* Test class for {@link MathUtil}.
*/
class MathUtilTest {

@ParameterizedTest
@ValueSource(doubles = {11.2D, 22.5678D, -1.2D})
void testTruncateDouble(final Double value) {
String result = Double.toString(MathUtil.truncateDouble(value, 1));
assertEquals(Double.toString(value).substring(0,4), result);
}

@ParameterizedTest(name = "truncate({0}, {1})")
@ValueSource(floats = {11.2F, 22.5678F, -1.2F})
void testTruncateFloat(final Float value) {
String result = Double.toString(MathUtil.truncateFloat(value, 1));
assertEquals(Float.toString(value).substring(0,4), result);
}

@ParameterizedTest
@ValueSource(longs = {2056L, -777L})
void testTruncateLong(final Long value) {
String result = Long.toString(MathUtil.truncateLong(value, 1));
assertEquals(Long.toString(value).substring(0,4), result);
}

@ParameterizedTest
@ValueSource(ints = {11, 22, -7})
void testTruncateInt(final int value) {
String result = Long.toString(MathUtil.truncateInt(value, 1));
assertEquals(Integer.toString(value).substring(0,2), result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,12 @@ public void ceil_int_value(Integer value) {
assertThat(
ceil.valueOf(valueEnv()),
allOf(hasType(INTEGER), hasValue((int) Math.ceil(value))));
assertEquals(String.format("ceil(%s)", value.toString()), ceil.toString());
assertEquals(String.format("ceil(%s)", value), ceil.toString());

FunctionExpression ceiling = DSL.ceiling(DSL.literal(value));
assertThat(
ceiling.valueOf(valueEnv()), allOf(hasType(INTEGER), hasValue((int) Math.ceil(value))));
assertEquals(String.format("ceiling(%s)", value.toString()), ceiling.toString());
assertEquals(String.format("ceiling(%s)", value), ceiling.toString());
}

/**
Expand All @@ -209,12 +209,12 @@ public void ceil_long_value(Long value) {
FunctionExpression ceil = DSL.ceil(DSL.literal(value));
assertThat(
ceil.valueOf(valueEnv()), allOf(hasType(INTEGER), hasValue((int) Math.ceil(value))));
assertEquals(String.format("ceil(%s)", value.toString()), ceil.toString());
assertEquals(String.format("ceil(%s)", value), ceil.toString());

FunctionExpression ceiling = DSL.ceiling(DSL.literal(value));
assertThat(
ceiling.valueOf(valueEnv()), allOf(hasType(INTEGER), hasValue((int) Math.ceil(value))));
assertEquals(String.format("ceiling(%s)", value.toString()), ceiling.toString());
assertEquals(String.format("ceiling(%s)", value), ceiling.toString());
}

/**
Expand All @@ -226,12 +226,12 @@ public void ceil_float_value(Float value) {
FunctionExpression ceil = DSL.ceil(DSL.literal(value));
assertThat(
ceil.valueOf(valueEnv()), allOf(hasType(INTEGER), hasValue((int) Math.ceil(value))));
assertEquals(String.format("ceil(%s)", value.toString()), ceil.toString());
assertEquals(String.format("ceil(%s)", value), ceil.toString());

FunctionExpression ceiling = DSL.ceiling(DSL.literal(value));
assertThat(
ceiling.valueOf(valueEnv()), allOf(hasType(INTEGER), hasValue((int) Math.ceil(value))));
assertEquals(String.format("ceiling(%s)", value.toString()), ceiling.toString());
assertEquals(String.format("ceiling(%s)", value), ceiling.toString());
}

/**
Expand All @@ -243,12 +243,12 @@ public void ceil_double_value(Double value) {
FunctionExpression ceil = DSL.ceil(DSL.literal(value));
assertThat(
ceil.valueOf(valueEnv()), allOf(hasType(INTEGER), hasValue((int) Math.ceil(value))));
assertEquals(String.format("ceil(%s)", value.toString()), ceil.toString());
assertEquals(String.format("ceil(%s)", value), ceil.toString());

FunctionExpression ceiling = DSL.ceiling(DSL.literal(value));
assertThat(
ceiling.valueOf(valueEnv()), allOf(hasType(INTEGER), hasValue((int) Math.ceil(value))));
assertEquals(String.format("ceiling(%s)", value.toString()), ceiling.toString());
assertEquals(String.format("ceiling(%s)", value), ceiling.toString());
}

/**
Expand Down Expand Up @@ -1721,51 +1721,51 @@ public void sqrt_missing_value() {
* Test truncate with integer value.
*/
@ParameterizedTest(name = "truncate({0}, {1})")
@ValueSource(ints = {2, -2})
@ValueSource(ints = {2, -2, Integer.MAX_VALUE, Integer.MIN_VALUE})
public void truncate_int_value(Integer value) {
FunctionExpression truncate = DSL.truncate(DSL.literal(value), DSL.literal(1));
assertThat(
truncate.valueOf(valueEnv()), allOf(hasType(LONG),
hasValue(new BigDecimal(value).setScale(1, RoundingMode.DOWN).longValue())));
hasValue(MathUtil.truncateInt(value, 1))));
assertEquals(String.format("truncate(%s, 1)", value), truncate.toString());
}

/**
* Test truncate with long value.
*/
@ParameterizedTest(name = "truncate({0}, {1})")
@ValueSource(longs = {2L, -2L})
@ValueSource(longs = {2L, -2L, Long.MAX_VALUE, Long.MIN_VALUE})
public void truncate_long_value(Long value) {
FunctionExpression truncate = DSL.truncate(DSL.literal(value), DSL.literal(1));
assertThat(
truncate.valueOf(valueEnv()), allOf(hasType(LONG),
hasValue(new BigDecimal(value).setScale(1, RoundingMode.DOWN).longValue())));
hasValue(MathUtil.truncateLong(value, 1))));
assertEquals(String.format("truncate(%s, 1)", value), truncate.toString());
}

/**
* Test truncate with float value.
*/
@ParameterizedTest(name = "truncate({0}, {1})")
@ValueSource(floats = {2F, -2F})
@ValueSource(floats = {2F, -2F, Float.MAX_VALUE, Float.MIN_VALUE})
public void truncate_float_value(Float value) {
FunctionExpression truncate = DSL.truncate(DSL.literal(value), DSL.literal(1));
assertThat(
truncate.valueOf(valueEnv()), allOf(hasType(DOUBLE),
hasValue(new BigDecimal(value).setScale(1, RoundingMode.DOWN).doubleValue())));
hasValue(MathUtil.truncateFloat(value, 1))));
assertEquals(String.format("truncate(%s, 1)", value), truncate.toString());
}

/**
* Test truncate with double value.
*/
@ParameterizedTest(name = "truncate({0}, {1})")
@ValueSource(doubles = {2D, -2D})
@ValueSource(doubles = {2D, -1.2D, Double.MAX_VALUE, Double.MIN_VALUE})
Comment thread
acarbonetto marked this conversation as resolved.
Outdated
public void truncate_double_value(Double value) {
FunctionExpression truncate = DSL.truncate(DSL.literal(value), DSL.literal(1));
assertThat(
truncate.valueOf(valueEnv()), allOf(hasType(DOUBLE),
hasValue(new BigDecimal(value).setScale(1, RoundingMode.DOWN).doubleValue())));
hasValue(MathUtil.truncateDouble(value, 1))));
assertEquals(String.format("truncate(%s, 1)", value), truncate.toString());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ public void testTruncate() throws IOException {
result = executeQuery("select truncate(-56, -1)");
verifySchema(result, schema("truncate(-56, -1)", null, "long"));
verifyDataRows(result, rows(-50));

result = executeQuery("select truncate(-1.2, 1)");
verifySchema(result, schema("truncate(-1.2, 1)", null, "double"));
verifyDataRows(result, rows(-1.2));

result = executeQuery("select truncate(1004.3, 1)");
verifySchema(result, schema("truncate(1004.3, 1)", null, "double"));
verifyDataRows(result, rows(1004.3));
}

@Test
Expand Down