Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 03ba51703a6d
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0058cf05dd8f
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Jul 17, 2017

  1. Copy the full SHA
    fab4883 View commit details
  2. Copy the full SHA
    0058cf0 View commit details
Showing with 69 additions and 38 deletions.
  1. +66 −38 core/src/main/java/org/jruby/ext/bigdecimal/RubyBigDecimal.java
  2. +3 −0 test/mri/excludes/TestBigDecimal.rb
104 changes: 66 additions & 38 deletions core/src/main/java/org/jruby/ext/bigdecimal/RubyBigDecimal.java
Original file line number Diff line number Diff line change
@@ -96,7 +96,7 @@ public RubyBigDecimal allocate(Ruby runtime, RubyClass klass) {
@JRubyConstant
public final static int SIGN_POSITIVE_INFINITE = 3;
@JRubyConstant
public final static int EXCEPTION_OVERFLOW = 8;
public final static int EXCEPTION_OVERFLOW = 1; // Note: This is same as EXCEPTION_INFINITY in MRI now
@JRubyConstant
public final static int SIGN_POSITIVE_ZERO = 1;
@JRubyConstant
@@ -306,10 +306,11 @@ private static IRubyObject modeExecute(final ThreadContext context, final RubyMo

@JRubyMethod(required = 1, optional = 1, meta = true)
public static IRubyObject mode(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;

// FIXME: I doubt any of the constants referenced in this method
// are ever redefined -- should compare to the known values, rather
// than do an expensive constant lookup.
RubyClass clazz = context.runtime.getClass("BigDecimal");
RubyModule c = (RubyModule)recv;

args = Arity.scanArgs(context.runtime, args, 1, 1);
@@ -322,55 +323,48 @@ public static IRubyObject mode(ThreadContext context, IRubyObject recv, IRubyObj
}

long longMode = ((RubyFixnum)mode).getLongValue();
long _EXCEPTION_ALL = bigDecimalConst(context.runtime, "EXCEPTION_ALL");
if ((longMode & _EXCEPTION_ALL) != 0) {
if ((longMode & EXCEPTION_ALL) != 0) {
if (value.isNil()) return c.searchInternalModuleVariable("vpExceptionMode");
if (!(value instanceof RubyBoolean)) throw context.runtime.newArgumentError("second argument must be true or false");

RubyFixnum newExceptionMode = (RubyFixnum)c.searchInternalModuleVariable("vpExceptionMode");
long newExceptionMode = c.searchInternalModuleVariable("vpExceptionMode").convertToInteger().getLongValue();

boolean enable = value.isTrue();

RubyFixnum _EXCEPTION_INFINITY = (RubyFixnum)clazz.getConstant("EXCEPTION_INFINITY");
if ((longMode & _EXCEPTION_INFINITY.getLongValue()) != 0) {
newExceptionMode = enable ? (RubyFixnum)newExceptionMode.callCoerced(context, sites(context).op_or, _EXCEPTION_INFINITY)
: (RubyFixnum)newExceptionMode.callCoerced(context, sites(context).op_and, new RubyFixnum(context.runtime, ~(_EXCEPTION_INFINITY).getLongValue()));
if ((longMode & EXCEPTION_INFINITY) != 0) {
newExceptionMode = enable ? newExceptionMode | EXCEPTION_INFINITY : newExceptionMode & ~(EXCEPTION_INFINITY);
}

RubyFixnum _EXCEPTION_NaN = (RubyFixnum)clazz.getConstant("EXCEPTION_NaN");
if ((longMode & _EXCEPTION_NaN.getLongValue()) != 0) {
newExceptionMode = enable ? (RubyFixnum)newExceptionMode.callCoerced(context, sites(context).op_or, _EXCEPTION_NaN)
: (RubyFixnum)newExceptionMode.callCoerced(context, sites(context).op_and, new RubyFixnum(context.runtime, ~(_EXCEPTION_NaN).getLongValue()));
if ((longMode & EXCEPTION_NaN) != 0) {
newExceptionMode = enable ? newExceptionMode | EXCEPTION_NaN : newExceptionMode & ~(EXCEPTION_NaN);
}

RubyFixnum _EXCEPTION_UNDERFLOW = (RubyFixnum)clazz.getConstant("EXCEPTION_UNDERFLOW");
if ((longMode & _EXCEPTION_UNDERFLOW.getLongValue()) != 0) {
newExceptionMode = enable ? (RubyFixnum)newExceptionMode.callCoerced(context, sites(context).op_or, _EXCEPTION_UNDERFLOW)
: (RubyFixnum)newExceptionMode.callCoerced(context, sites(context).op_and, new RubyFixnum(context.runtime, ~(_EXCEPTION_UNDERFLOW).getLongValue()));
if ((longMode & EXCEPTION_UNDERFLOW) != 0) {
newExceptionMode = enable ? newExceptionMode | EXCEPTION_UNDERFLOW : newExceptionMode & ~(EXCEPTION_UNDERFLOW);
}

RubyFixnum _EXCEPTION_OVERFLOW = (RubyFixnum)clazz.getConstant("EXCEPTION_OVERFLOW");
if ((longMode & _EXCEPTION_OVERFLOW.getLongValue()) != 0) {
newExceptionMode = enable ? (RubyFixnum)newExceptionMode.callCoerced(context, sites(context).op_or, _EXCEPTION_OVERFLOW)
: (RubyFixnum)newExceptionMode.callCoerced(context, sites(context).op_and, new RubyFixnum(context.runtime, ~(_EXCEPTION_OVERFLOW).getLongValue()));
if ((longMode & EXCEPTION_ZERODIVIDE) != 0) {
newExceptionMode = enable ? newExceptionMode | EXCEPTION_ZERODIVIDE : newExceptionMode & ~(EXCEPTION_ZERODIVIDE);
}
c.setInternalModuleVariable("vpExceptionMode", newExceptionMode);
return newExceptionMode;

RubyFixnum fixnumMode = RubyFixnum.newFixnum(runtime, newExceptionMode);
c.setInternalModuleVariable("vpExceptionMode", fixnumMode);
return fixnumMode;
}

long ROUND_MODE = ((RubyFixnum)clazz.getConstant("ROUND_MODE")).getLongValue();
if (longMode == ROUND_MODE) {
if (value.isNil()) {
return c.searchInternalModuleVariable("vpRoundingMode");
}

RoundingMode javaRoundingMode = javaRoundingModeFromRubyRoundingMode(context.runtime, value);
RubyFixnum roundingMode = context.runtime.newFixnum(javaRoundingMode.ordinal());
RoundingMode javaRoundingMode = javaRoundingModeFromRubyRoundingMode(runtime, value);
RubyFixnum roundingMode = runtime.newFixnum(javaRoundingMode.ordinal());
c.setInternalModuleVariable("vpRoundingMode", roundingMode);

return c.searchInternalModuleVariable("vpRoundingMode");
}
throw context.runtime.newTypeError("first argument for BigDecimal#mode invalid");

throw runtime.newTypeError("first argument for BigDecimal#mode invalid");
}

private static RubyModule bigDecimal(Ruby runtime) {
@@ -392,15 +386,15 @@ private static RoundingMode getRoundingMode(Ruby runtime) {
}

private static boolean isNaNExceptionMode(Ruby runtime) {
return (bigDecimalVar(runtime, "vpExceptionMode") & bigDecimalConst(runtime, "EXCEPTION_NaN")) != 0;
return (bigDecimalVar(runtime, "vpExceptionMode") & EXCEPTION_NaN) != 0;
}

private static boolean isInfinityExceptionMode(Ruby runtime) {
return (bigDecimalVar(runtime, "vpExceptionMode") & bigDecimalConst(runtime, "EXCEPTION_INFINITY")) != 0;
return (bigDecimalVar(runtime, "vpExceptionMode") & EXCEPTION_INFINITY) != 0;
}

private static boolean isOverflowExceptionMode(Ruby runtime) {
return (bigDecimalVar(runtime, "vpExceptionMode") & bigDecimalConst(runtime, "EXCEPTION_OVERFLOW")) != 0;
return (bigDecimalVar(runtime, "vpExceptionMode") & EXCEPTION_OVERFLOW) != 0;
}

private static RubyBigDecimal cannotBeCoerced(ThreadContext context, IRubyObject value, boolean must) {
@@ -1357,6 +1351,8 @@ public IRubyObject precs(ThreadContext context) {

@JRubyMethod(name = "round", optional = 2)
public IRubyObject round(ThreadContext context, IRubyObject[] args) {
Ruby runtime = context.runtime;

// Special treatment for BigDecimal::NAN and BigDecimal::INFINITY
//
// If round is called without any argument, we should raise a
@@ -1366,16 +1362,30 @@ public IRubyObject round(ThreadContext context, IRubyObject[] args) {
StringBuilder message = new StringBuilder("Computation results to ");
message.append('\'').append(callMethod(context, "to_s")).append('\'');

throw context.runtime.newFloatDomainError(message.toString());
throw runtime.newFloatDomainError(message.toString());
} else {
if (isNaN()) return newNaN(context.runtime);
if (isNaN()) return newNaN(runtime);
if (isInfinity()) {
return newInfinity(context.runtime, infinitySign);
return newInfinity(runtime, infinitySign);
}
}

final int scale = args.length > 0 ? num2int(args[0]) : 0;
RoundingMode mode = (args.length > 1) ? javaRoundingModeFromRubyRoundingMode(context.runtime, args[1]) : getRoundingMode(context.runtime);
RoundingMode mode = getRoundingMode(runtime);
int scale = 0;

int argc = args.length;
switch (argc) {
case 2:
mode = javaRoundingModeFromRubyRoundingMode(runtime, args[1]);
scale = num2int(args[0]);
case 1:
if (ArgsUtil.getOptionsArg(runtime, args[0]).isNil()) {
scale = num2int(args[0]);
} else {
mode = javaRoundingModeFromRubyRoundingMode(runtime, args[0]);
}
}

// JRUBY-914: Java 1.4 BigDecimal does not allow a negative scale, so we have to simulate it
final RubyBigDecimal bigDecimal;
if (scale < 0) {
@@ -1385,9 +1395,9 @@ public IRubyObject round(ThreadContext context, IRubyObject[] args) {
// ...round to that digit
BigDecimal rounded = normalized.setScale(0, mode);
// ...and shift the result back to the left (multiply by 10**(abs(scale)))
bigDecimal = new RubyBigDecimal(context.runtime, rounded.movePointLeft(scale));
bigDecimal = new RubyBigDecimal(runtime, rounded.movePointLeft(scale));
} else {
bigDecimal = new RubyBigDecimal(context.runtime, value.setScale(scale, mode));
bigDecimal = new RubyBigDecimal(runtime, value.setScale(scale, mode));
}

return args.length == 0 ? bigDecimal.to_int() : bigDecimal;
@@ -1402,6 +1412,23 @@ private static RoundingMode javaRoundingModeFromRubyRoundingMode(Ruby runtime, I
IRubyObject opts = ArgsUtil.getOptionsArg(runtime, arg);
if (!opts.isNil()) {
arg = ArgsUtil.extractKeywordArg(runtime.getCurrentContext(), "half", opts);
if (arg.isNil()) {
return getRoundingMode(runtime);
}
String roundingMode = arg.asJavaString();
switch (roundingMode) {
case "up":
return RoundingMode.HALF_UP;
case "down" :
return RoundingMode.HALF_DOWN;
case "even" :
return RoundingMode.HALF_EVEN;
default :
throw runtime.newArgumentError("invalid rounding mode: " + roundingMode);
}
}
if (arg.isNil()) {
return getRoundingMode(runtime);
}
if (arg instanceof RubySymbol) {
String roundingMode = arg.asJavaString();
@@ -1417,6 +1444,7 @@ private static RoundingMode javaRoundingModeFromRubyRoundingMode(Ruby runtime, I
case "half_down" :
return RoundingMode.HALF_DOWN;
case "half_even" :
case "even" :
case "banker" :
return RoundingMode.HALF_EVEN;
case "ceiling" :
@@ -1425,7 +1453,7 @@ private static RoundingMode javaRoundingModeFromRubyRoundingMode(Ruby runtime, I
case "floor" :
return RoundingMode.FLOOR;
default :
throw runtime.newArgumentError("invalid rounding mode");
throw runtime.newArgumentError("invalid rounding mode: " + roundingMode);
}
} else {
try {
3 changes: 3 additions & 0 deletions test/mri/excludes/TestBigDecimal.rb
Original file line number Diff line number Diff line change
@@ -6,8 +6,11 @@
exclude :test_exception_underflow, "needs investigation"

exclude :test_global_new_with_float, "needs investigation"
exclude :test_global_new_with_invalid_string, "error change in 2.4?"
exclude :test_limit, "needs investigation"
exclude :test_marshal, "needs investigation"
exclude :test_mult, "error change in 2.4?"
exclude :test_new, "stricter parsing in 2.4"

exclude :test_power_of_negative_infinity, "needs investigation"
exclude :test_power_of_positive_infinity, "needs investigation"