Skip to content

Commit

Permalink
Handle fractionDigits negative case
Browse files Browse the repository at this point in the history
  • Loading branch information
KavinduZoysa committed Apr 7, 2022
1 parent 53a7927 commit 0a895dc
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 2,212 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ public class BallerinaErrorReasons {
public static final BString UNORDERED_TYPES_ERROR = StringUtils.fromString(UNORDERED_TYPES);
public static final BString UNSUPPORTED_DECIMAL_ERROR = StringUtils.fromString(BALLERINA_PREFIX.concat(
"UnsupportedDecimalError"));
public static final String NEGATIVE_FRACTION_DIGITS = "NegativeFractionDigits";

public static BString getModulePrefixedReason(String moduleName, String identifier) {
return StringUtils.fromString(BALLERINA_ORG_PREFIX.concat(moduleName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,7 @@ public enum RuntimeErrors implements DiagnosticCode {
CONFIG_CLI_ARGS_AMBIGUITY("config.cli.args.ambiguity", "RUNTIME_0094"),
CONFIG_CLI_UNUSED_CLI_ARGS("config.cli.unused.args", "RUNTIME_0095"),
LARGE_EXPONENTS_IN_DECIMAL("large.number.of.exponents.in.decimal", "RUNTIME_0096"),
UNSUPPORTED_DECIMAL_VALUE("unsupported.decimal.value", "RUNTIME_0097"),
FRACTION_DIGITS_NOT_NEGATIVE("fraction.digits.not.negative", "RUNTIME_0098");
UNSUPPORTED_DECIMAL_VALUE("unsupported.decimal.value", "RUNTIME_0097");

private String errorMsgKey;
private String errorCode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,3 @@ config.cli.args.ambiguity = configurable value for variable ''{0}'' clashes with
config.cli.unused.args = [{0}] unused command line argument
large.number.of.exponents.in.decimal = too many exponents found in decimal value ''{0}''
unsupported.decimal.value = decimal operation resulting in unsupported decimal value ''{0}''
fraction.digits.not.negative = fraction digits cannot be negative
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,9 @@

package org.ballerinalang.langlib.floatingpoint;

import io.ballerina.runtime.internal.util.exceptions.BLangExceptionHelper;
import io.ballerina.runtime.internal.util.exceptions.RuntimeErrors;

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

import static io.ballerina.runtime.api.constants.RuntimeConstants.FLOAT_LANG_LIB;
import static io.ballerina.runtime.internal.util.exceptions.BallerinaErrorReasons.NEGATIVE_FRACTION_DIGITS;
import static io.ballerina.runtime.internal.util.exceptions.BallerinaErrorReasons.getModulePrefixedReason;

/**
* Native implementation of lang.float:round(float, int).
*
Expand All @@ -45,11 +38,6 @@ public static double round(double x, long fractionDigits) {
if (isSpecialValue(x)) {
return x;
}
if (fractionDigits < 0) {
throw BLangExceptionHelper.getRuntimeException(
getModulePrefixedReason(FLOAT_LANG_LIB, NEGATIVE_FRACTION_DIGITS),
RuntimeErrors.FRACTION_DIGITS_NOT_NEGATIVE);
}
if (fractionDigits == 0) {
return Math.rint(x);
}
Expand All @@ -59,16 +47,28 @@ public static double round(double x, long fractionDigits) {
// Therefore, if `fractionDigits` is very large, `x` will not be changed.
return x;
}
if (fractionDigits < Integer.MIN_VALUE) {
return 0;
}
// Down cast can be done safely because of above condition.
int fractionDigitsAsInt = (int) fractionDigits;
BigDecimal xInBigDecimal = BigDecimal.valueOf(x);
BigDecimal xTmp = xInBigDecimal;
int digitsTmp = fractionDigitsAsInt;
while (digitsTmp-- > 0) {
if (xTmp.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) == 0) {
return x;
if (digitsTmp > 0) {
while (digitsTmp-- > 0) {
if (xTmp.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) == 0) {
return x;
}
xTmp = xTmp.multiply(BigDecimal.TEN);
}
} else {
while (digitsTmp++ < 0) {
if (xTmp.compareTo(BigDecimal.ZERO) == 0) {
return 0;
}
xTmp = xTmp.divide(BigDecimal.TEN, 0, RoundingMode.DOWN);
}
xTmp = xTmp.multiply(BigDecimal.TEN);
}
return xInBigDecimal.setScale(fractionDigitsAsInt, RoundingMode.HALF_EVEN).doubleValue();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
package org.ballerinalang.langlib.test;

import io.ballerina.runtime.api.values.BArray;
import io.ballerina.runtime.internal.util.exceptions.BLangRuntimeException;
import org.ballerinalang.test.BCompileUtil;
import org.ballerinalang.test.BRunUtil;
import org.ballerinalang.test.CompileResult;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
Expand Down Expand Up @@ -132,20 +130,4 @@ public Object[] functionsToTestRound() {
"testRound"
};
}

@Test(expectedExceptions = BLangRuntimeException.class,
expectedExceptionsMessageRegExp = "error: \\{ballerina/lang.float}NegativeFractionDigits " +
"\\{\"message\":\"fraction digits cannot be negative\"}.*")
public void testRoundNegative1() {
BRunUtil.invoke(compileResult, "testRoundNegative1");
Assert.fail();
}

@Test(expectedExceptions = BLangRuntimeException.class,
expectedExceptionsMessageRegExp = "error: \\{ballerina/lang.float}NegativeFractionDigits " +
"\\{\"message\":\"fraction digits cannot be negative\"}.*")
public void testRoundNegative2() {
BRunUtil.invoke(compileResult, "testRoundNegative2");
Assert.fail();
}
}
80 changes: 65 additions & 15 deletions langlib/langlib-test/src/test/resources/test-src/floatlib_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -459,11 +459,11 @@ function testRound() {
assertEquality(float:round(1.123456e12f, 1), 1.123456e12f);
assertEquality(float:round(1.123456e12f, 7), 1.123456e12f);

assertEquality(float:round(1.123456e2f, 1), 112.3f); // 112.3456, 1 => 112.3 => X*10^-1 = 1123*10^-1
assertEquality(float:round(1.123456e2f, 2), 112.35f); // 112.3456, 2 => 112.35 => X*10^-2 = 11235*10^-2
assertEquality(float:round(1.123456e2f, 3), 112.346f); // 112.3456, 3 => 112.346 => X*10^-2 = 11235*10^-2
assertEquality(float:round(1.12345e2f, 3), 112.345f); // 112.345, 3 => 112.346 => X*10^-2 = 11235*10^-2
assertEquality(float:round(1.12345e2f, 20), 112.345f); // 112.345, 20 => 112.346 => X*10^-2 = 11235*10^-2
assertEquality(float:round(1.123456e2f, 1), 112.3f);
assertEquality(float:round(1.123456e2f, 2), 112.35f);
assertEquality(float:round(1.123456e2f, 3), 112.346f);
assertEquality(float:round(1.12345e2f, 3), 112.345f);
assertEquality(float:round(1.12345e2f, 20), 112.345f);

assertEquality(float:round(5.0e2f, 2), 5.0e2f);

Expand Down Expand Up @@ -513,26 +513,76 @@ function testRound() {
assertEquality(float:round(2.3e307f), 2.3e307f);
assertEquality(float:round(2.335e-307f), 0.0f);

assertEquality(float:round(123.123f, -2), 100.0);
assertEquality(float:round(123.123f, -3), 0.0);
assertEquality(float:round(123.123f, -4), 0.0);

assertEquality(float:round(12.5f, -1), 10.0);
assertEquality(float:round(235.5f, -1), 240.0);
assertEquality(float:round(250.0f, -1), 250.0);
assertEquality(float:round(251.0f, -1), 250.0);
assertEquality(float:round(251.0f, -2), 300.0);
assertEquality(float:round(251.0f, -3), 0.0);
assertEquality(float:round(251.0f, -4), 0.0);

assertEquality(float:round(999.9f, -3), 1000.0);
assertEquality(float:round(999.9f, -4), 0.0);

assertEquality(float:round(555.555f, -2), 600.0);
assertEquality(float:round(555.555f, -3), 1000.0);
assertEquality(float:round(555.555f, -4), 0.0);

assertEquality(float:round(765f, -2), 800.0);

assertEquality(float:round(0.1234f, -1), 0.0);
assertEquality(float:round(0.1234f, -5), 0.0);
assertEquality(float:round(0.1555f, -1), 0.0);
assertEquality(float:round(0.1555f, -4), 0.0);
assertEquality(float:round(0.001234f, -2), 0.0);
assertEquality(float:round(0.001234f, -7), 0.0);
assertEquality(float:round(1.123456e2f, -1), 110.0);
assertEquality(float:round(1.123456e2f, -2), 100.0);
assertEquality(float:round(1.123456e2f, -3), 0.0);
assertEquality(float:round(1.12345e2f, -3), 0.0);
assertEquality(float:round(1.12345e2f, -20), 0.0);

assertEquality(float:round(5.0e2f, 2), 500.0);

assertEquality(float:round(0.000055e2f, -2), 0.0);
assertEquality(float:round(0.00005e2f, -2), 0.0);
assertEquality(float:round(0.000055e20f, -2), 5.5e15f);

assertEquality(float:round(12345.67e-2f, -2), 100.0);
assertEquality(float:round(12345.0e-2f, -1), 120.0);
assertEquality(float:round(12345.0e-1f, -1), 1230.0);
assertEquality(float:round(12355.0e-1f, -1), 1240.0);
assertEquality(float:round(12345.67e-20f, -2), 0.0);

assertEquality(float:round(1.123456789123456999999f, -15), 0.0);

assertEquality(float:round(2.3e307f, -307), 2.0e307f);
assertEquality(float:round(2.335e307f, -2), 2.335e307);

assertEquality(float:round(0.1f, int:MIN_VALUE), 0.0);
assertEquality(float:round(-0.1f, int:MIN_VALUE), 0.0);
assertEquality(float:round(2.335e307f, int:MIN_VALUE), 0.0);
assertEquality(float:round(2.335e-307f, int:MIN_VALUE), 0.0);

float f = float:NaN;
assertEquality(float:round(f, 3), f);
assertEquality(float:round(f, -3), f);
f = -0.0f;
assertEquality(float:round(f, 3), f);
assertEquality(float:round(f, -3), f);
f = 0.0f;
assertEquality(float:round(f, 3), f);
assertEquality(float:round(f, -3), f);
f = float:Infinity;
assertEquality(float:round(f), f);
assertEquality(float:round(f, -2), f);
f = -float:Infinity;
assertEquality(float:round(f), f);

}

function testRoundNegative1() {
float _ = float:round(2.3f, -3); // runtime error
}

function testRoundNegative2() {
int fractionDigits = -1;
float _ = float:round(2.3f, fractionDigits); // runtime error
assertEquality(float:round(f, -2), f);
}

function assertEquality(any|error expected, any|error actual) {
Expand Down
Loading

0 comments on commit 0a895dc

Please sign in to comment.