Skip to content

Commit

Permalink
Showing 6 changed files with 98 additions and 27 deletions.
4 changes: 2 additions & 2 deletions core/src/main/java/org/jruby/RubyRational.java
Original file line number Diff line number Diff line change
@@ -129,7 +129,7 @@ private RubyRational(Ruby runtime, IRubyObject clazz, IRubyObject num, IRubyObje
/** rb_rational_raw
*
*/
static RubyRational newRationalRaw(Ruby runtime, IRubyObject x, IRubyObject y) {
public static RubyRational newRationalRaw(Ruby runtime, IRubyObject x, IRubyObject y) {
return new RubyRational(runtime, runtime.getRational(), x, y);
}

@@ -150,7 +150,7 @@ static IRubyObject newRationalCanonicalize(ThreadContext context, IRubyObject x)
/** rb_rational_new
*
*/
static IRubyObject newRationalCanonicalize(ThreadContext context, IRubyObject x, IRubyObject y) {
public static IRubyObject newRationalCanonicalize(ThreadContext context, IRubyObject x, IRubyObject y) {
return canonicalizeInternal(context, context.runtime.getRational(), x, y);
}

Original file line number Diff line number Diff line change
@@ -423,12 +423,16 @@ private static RubyBigDecimal getVpValue19(ThreadContext context, IRubyObject v,
}

private static RubyBigDecimal getVpRubyObjectWithPrec19Inner(ThreadContext context, RubyRational value) {
return getVpRubyObjectWithPrec19Inner(context, value, getRoundingMode(context.runtime));
}

public static RubyBigDecimal getVpRubyObjectWithPrec19Inner(ThreadContext context, RubyRational value, RoundingMode roundingMode) {
BigDecimal numerator = BigDecimal.valueOf(RubyNumeric.num2long(value.numerator(context)));
BigDecimal denominator = BigDecimal.valueOf(RubyNumeric.num2long(value.denominator(context)));

int len = numerator.precision() + denominator.precision();
int pow = len / 4;
MathContext mathContext = new MathContext((pow + 1) * 4, getRoundingMode(context.runtime));
MathContext mathContext = new MathContext((pow + 1) * 4, roundingMode);

return new RubyBigDecimal(context.runtime, numerator.divide(denominator, mathContext));
}
1 change: 1 addition & 0 deletions spec/truffle/tags/library/bigdecimal/add_tags.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
fails:BigDecimal#add raises ArgumentError when precision parameter is negative
fails:BigDecimal#add raises TypeError when adds nil
2 changes: 2 additions & 0 deletions spec/truffle/tags/library/bigdecimal/divmod_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fails:BigDecimal#mod_part_of_divmod raises TypeError if the argument cannot be coerced to BigDecimal
fails:BigDecimal#divmod raises TypeError if the argument cannot be coerced to BigDecimal
2 changes: 2 additions & 0 deletions spec/truffle/tags/library/bigdecimal/modulo_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fails:BigDecimal#% raises TypeError if the argument cannot be coerced to BigDecimal
fails:BigDecimal#modulo raises TypeError if the argument cannot be coerced to BigDecimal
110 changes: 86 additions & 24 deletions truffle/src/main/java/org/jruby/truffle/nodes/ext/BigDecimalNodes.java
Original file line number Diff line number Diff line change
@@ -17,6 +17,8 @@
import com.oracle.truffle.api.utilities.ConditionProfile;
import com.oracle.truffle.api.source.SourceSection;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.RubyFixnum;
import org.jruby.RubyRational;
import org.jruby.ext.bigdecimal.RubyBigDecimal;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyGuards;
@@ -251,7 +253,7 @@ public abstract static class CreateBigDecimalNode extends BigDecimalCoreMethodNo

public CreateBigDecimalNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
bigDecimalCast = BigDecimalCastNodeGen.create(context, sourceSection, null);
bigDecimalCast = BigDecimalCastNodeGen.create(context, sourceSection, null, null);
}

private void setBigDecimalValue(DynamicObject bigdecimal, BigDecimal value) {
@@ -282,7 +284,7 @@ public DynamicObject create(VirtualFrame frame, long value, DynamicObject self,
@Specialization
public DynamicObject create(VirtualFrame frame, long value, DynamicObject self, int digits) {
setBigDecimalValue(self,
bigDecimalCast.executeBigDecimal(frame, value).round(new MathContext(digits, getRoundMode(frame))));
bigDecimalCast.executeBigDecimal(frame, value, getRoundMode(frame)).round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@@ -295,7 +297,7 @@ public DynamicObject create(VirtualFrame frame, double value, DynamicObject self
@Specialization
public DynamicObject create(VirtualFrame frame, double value, DynamicObject self, int digits) {
setBigDecimalValue(self,
bigDecimalCast.executeBigDecimal(frame, value).round(new MathContext(digits, getRoundMode(frame))));
bigDecimalCast.executeBigDecimal(frame, value, getRoundMode(frame)).round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@@ -361,7 +363,7 @@ public DynamicObject createString(VirtualFrame frame, DynamicObject value, Dynam

@Specialization(guards = { "!isRubyBignum(value)", "!isRubyBigDecimal(value)", "!isRubyString(value)" })
public DynamicObject create(VirtualFrame frame, DynamicObject value, DynamicObject self, int digits) {
final Object castedValue = bigDecimalCast.executeObject(frame, value);
final Object castedValue = bigDecimalCast.executeObject(frame, value, getRoundMode(frame));
if (castedValue == nil()) {
throw new RaiseException(getContext().getCoreLibrary().typeError("could not be casted to BigDecimal", this));
}
@@ -2063,52 +2065,97 @@ public int toISpecial(DynamicObject value) {
/**
* Casts a value into a BigDecimal.
*/
@NodeChild(value = "value", type = RubyNode.class)
@NodeChildren({
@NodeChild(value = "value", type = RubyNode.class),
@NodeChild(value = "roundingMode", type = RubyNode.class)
})
@ImportStatic(BigDecimalCoreMethodNode.class)
public abstract static class BigDecimalCastNode extends RubyNode {
public BigDecimalCastNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public abstract BigDecimal executeBigDecimal(VirtualFrame frame, Object value);
public abstract BigDecimal executeBigDecimal(VirtualFrame frame, Object value, RoundingMode roundingMode);

public abstract Object executeObject(VirtualFrame frame, Object value);
public abstract Object executeObject(VirtualFrame frame, Object value, RoundingMode roundingMode);

@Specialization
public BigDecimal doInt(long value) {
public BigDecimal doInt(long value, Object roundingMode) {
return BigDecimal.valueOf(value);
}

@Specialization
public BigDecimal doDouble(double value) {
public BigDecimal doDouble(double value, Object roundingMode) {
return BigDecimal.valueOf(value);
}

@Specialization(guards = "isRubyBignum(value)")
public BigDecimal doBignum(DynamicObject value) {
public BigDecimal doBignum(DynamicObject value, Object roundingMode) {
return new BigDecimal(Layouts.BIGNUM.getValue(value));
}

@Specialization(guards = "isNormalRubyBigDecimal(value)")
public BigDecimal doBigDecimal(DynamicObject value) {
public BigDecimal doBigDecimal(DynamicObject value, Object roundingMode) {
return Layouts.BIG_DECIMAL.getValue(value);
}

@Specialization(guards = { "!isRubyBignum(value)", "!isRubyBigDecimal(value)" })
public Object doOther(VirtualFrame frame, DynamicObject value) {
final Object result = ruby(
public Object doOther(VirtualFrame frame, DynamicObject value, Object roundingMode) {
if (roundingMode instanceof RoundingMode && (boolean) ruby(
frame,
"value.is_a?(Rational) ? value.to_f : nil",
"value", value);
if (result != nil()) {
return new BigDecimal((double) result);
"value.is_a?(Rational)",
"value", value)) {

final Object numerator = ruby(
frame,
"value.numerator",
"value", value);

final long numeratorValue;

if (numerator instanceof Integer) {
numeratorValue = (int) numerator;
} else if (numerator instanceof Long) {
numeratorValue = (long) numerator;
} else {
throw new UnsupportedOperationException();
}

final Object denominator = ruby(
frame,
"value.denominator",
"value", value);

final long denominatorValue;

if (denominator instanceof Integer) {
denominatorValue = (int) denominator;
} else if (denominator instanceof Long) {
denominatorValue = (long) denominator;
} else {
throw new UnsupportedOperationException();
}

final RubyRational rubyRationalValue = RubyRational.newRationalRaw(getContext().getRuntime(), RubyFixnum.newFixnum(getContext().getRuntime(), numeratorValue), RubyFixnum.newFixnum(getContext().getRuntime(), denominatorValue));

final RubyBigDecimal rubyBigDecimalValue = RubyBigDecimal.getVpRubyObjectWithPrec19Inner(getContext().getRuntime().getCurrentContext(), rubyRationalValue, (RoundingMode) roundingMode);

return rubyBigDecimalValue.getBigDecimalValue();
} else {
return result;
final Object result = ruby(
frame,
"value.to_f",
"value", value);
if (result != nil()) {
return new BigDecimal((double) result);
} else {
return result;
}
}
}

@Fallback
public Object doBigDecimalFallback(Object value) {
public Object doBigDecimalFallback(Object value, Object roundingMode) {
return nil();
}
// TODO (pitr 22-Jun-2015): How to better communicate failure without throwing
@@ -2119,7 +2166,8 @@ public Object doBigDecimalFallback(Object value) {
*/
@NodeChildren({
@NodeChild(value = "value", type = RubyNode.class),
@NodeChild(value = "cast", type = BigDecimalCastNode.class, executeWith = "value")
@NodeChild(value = "roundingMode", type = RoundModeNode.class),
@NodeChild(value = "cast", type = BigDecimalCastNode.class, executeWith = {"value", "roundingMode"})

})
public abstract static class BigDecimalCoerceNode extends RubyNode {
@@ -2131,7 +2179,8 @@ public BigDecimalCoerceNode(RubyContext context, SourceSection sourceSection) {

public static BigDecimalCoerceNode create(RubyContext context, SourceSection sourceSection, RubyNode value) {
return BigDecimalCoerceNodeGen.create(context, sourceSection, value,
BigDecimalCastNodeGen.create(context, sourceSection, null));
BigDecimalNodesFactory.RoundModeNodeFactory.create(context, sourceSection),
BigDecimalCastNodeGen.create(context, sourceSection, null, null));
}

private void setupCreateBigDecimal() {
@@ -2146,15 +2195,15 @@ protected DynamicObject createBigDecimal(VirtualFrame frame, Object value) {
return createBigDecimal.executeCreate(frame, value);
}

public abstract DynamicObject executeBigDecimal(VirtualFrame frame, Object value);
public abstract DynamicObject executeBigDecimal(VirtualFrame frame, RoundingMode roundingMode, Object value);

@Specialization
public DynamicObject doBigDecimal(VirtualFrame frame, Object value, BigDecimal cast) {
public DynamicObject doBigDecimal(VirtualFrame frame, Object value, RoundingMode roundingMode, BigDecimal cast) {
return createBigDecimal(frame, cast);
}

@Specialization(guards = { "isRubyBigDecimal(value)", "isNil(cast)" })
public Object doBigDecimal(DynamicObject value, DynamicObject cast) {
public Object doBigDecimal(DynamicObject value, RoundingMode roundingMode, DynamicObject cast) {
return value;
}

@@ -2176,4 +2225,17 @@ public DynamicObject allocate(DynamicObject rubyClass) {

}

public abstract static class RoundModeNode extends BigDecimalCoreMethodNode {

public RoundModeNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Specialization
public RoundingMode doGetRoundMode(VirtualFrame frame) {
return getRoundMode(frame);
}

}

}

0 comments on commit eaa1b9f

Please sign in to comment.