Skip to content

Commit

Permalink
[Truffle] BigDecimal: fix remaining failing div tags
Browse files Browse the repository at this point in the history
  • Loading branch information
pitr-ch committed Jul 3, 2015
1 parent 8f83005 commit 40e74c4
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 16 deletions.
8 changes: 0 additions & 8 deletions spec/truffle/tags/library/bigdecimal/div_tags.txt

This file was deleted.

Expand Up @@ -158,6 +158,15 @@ private static int nearestBiggerMultipleOf4(int value) {
return ((value / 4) + 1) * 4;
}

public static int defaultDivisionPrecision(int precisionA, int precisionB, int limit) {
final int combination = nearestBiggerMultipleOf4(precisionA + precisionB) * 2;
return (limit > 0 && limit < combination) ? limit : combination;
}

public static int defaultDivisionPrecision(BigDecimal a, BigDecimal b, int limit) {
return defaultDivisionPrecision(a.precision(), b.precision(), limit);
}

public enum Type {
NEGATIVE_INFINITY("-Infinity"),
POSITIVE_INFINITY("Infinity"),
Expand Down Expand Up @@ -420,6 +429,7 @@ public RubyBasicObject createBigDecimal(VirtualFrame frame, RubyBasicObject valu
}
}

// TODO (pitr 21-Jun-2015): Check for missing coerce on OpNodess

// TODO (pitr 30-may-2015): handle digits argument also for other types than just String
@CoreMethod(names = "initialize", required = 1, optional = 1)
Expand Down Expand Up @@ -528,8 +538,6 @@ private Object getValueFromString(String string, int digits) {
}
}

// TODO (pitr 21-Jun-2015): Check for missing coerce on OpNodess

@NodeChildren({
@NodeChild(value = "a", type = RubyNode.class),
@NodeChild(value = "b", type = RubyNode.class),
Expand Down Expand Up @@ -722,7 +730,6 @@ public Object subSpecial(VirtualFrame frame, RubyBasicObject a, RubyBasicObject
}
}


@CoreMethod(names = "-@")
public abstract static class NegNode extends BigDecimalCoreMethodArrayArgumentsNode {

Expand Down Expand Up @@ -1073,10 +1080,8 @@ public DivOpNode(RubyContext context, SourceSection sourceSection) {
"isNormal(a)",
"isNormalRubyBigDecimal(b)" })
public Object div(VirtualFrame frame, RubyBasicObject a, RubyBasicObject b) {
final int sumOfPrecisions = getBigDecimalValue(a).precision() + getBigDecimalValue(b).precision();
final int defaultPrecision = nearestBiggerMultipleOf4(sumOfPrecisions) * 2;
final int limit = getLimit(frame);
return div(frame, a, b, (limit > 0 && limit < defaultPrecision) ? limit : defaultPrecision);
final int precision = defaultDivisionPrecision(getBigDecimalValue(a), getBigDecimalValue(b), getLimit(frame));
return div(frame, a, b, precision);
}

@Specialization(guards = {
Expand Down Expand Up @@ -1105,15 +1110,58 @@ public Object divSpecialSpecial(VirtualFrame frame, RubyBasicObject a, RubyBasic
@NodeChild(value = "precision", type = RubyNode.class)
public abstract static class DivNode extends AbstractDivNode {

@Child private CallDispatchHeadNode floorCall;
private final ConditionProfile zeroPrecisionProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile bZeroProfile = ConditionProfile.createBinaryProfile();

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

private void setupFloorCall() {
if (floorCall == null) {
CompilerDirectives.transferToInterpreter();
floorCall = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}
}

@Specialization(guards = {
"isNormal(a)",
"isNormalRubyBigDecimal(b)" })
public Object div(VirtualFrame frame, RubyBasicObject a, RubyBasicObject b, NotProvided precision) {
setupFloorCall();
if (bZeroProfile.profile(isNormalZero(b))) {
throw new RaiseException(getContext().getCoreLibrary().zeroDivisionError(this));
} else {
final Object result = div(frame, a, b, 0);
return floorCall.call(frame, result, "floor", null);
}
}

@Specialization(guards = {
"isNormal(a)",
"isNormalRubyBigDecimal(b)" })
public Object div(VirtualFrame frame, RubyBasicObject a, RubyBasicObject b, int precision) {
return super.div(frame, a, b, precision);
final int newPrecision;
if (zeroPrecisionProfile.profile(precision == 0)) {
newPrecision = defaultDivisionPrecision(getBigDecimalValue(a), getBigDecimalValue(b), getLimit(frame));
} else {
newPrecision = precision;
}
return super.div(frame, a, b, newPrecision);
}

@Specialization(guards = {
"isNormal(a)",
"isSpecialRubyBigDecimal(b)" })
public Object divNormalSpecial(VirtualFrame frame, RubyBasicObject a, RubyBasicObject b, NotProvided precision) {
if (getBigDecimalType(b) == Type.NEGATIVE_ZERO) {
throw new RaiseException(getContext().getCoreLibrary().zeroDivisionError(this));
} else if (getBigDecimalType(b) == Type.NAN) {
throw new RaiseException(getContext().getCoreLibrary().floatDomainError("Computation results to 'NaN'(Not a Number)", this));
} else {
return divNormalSpecial(frame, a, b, 0);
}
}

@Specialization(guards = {
Expand All @@ -1123,13 +1171,41 @@ public Object divNormalSpecial(VirtualFrame frame, RubyBasicObject a, RubyBasicO
return super.divNormalSpecial(frame, a, b, precision);
}

@Specialization(guards = {
"!isNormal(a)",
"isNormalRubyBigDecimal(b)" })
public Object divSpecialNormal(VirtualFrame frame, RubyBasicObject a, RubyBasicObject b, NotProvided precision) {
if (isNormalZero(b)) {
throw new RaiseException(getContext().getCoreLibrary().zeroDivisionError(this));
} else if (getBigDecimalType(a) == Type.NAN) {
throw new RaiseException(getContext().getCoreLibrary().floatDomainError("Computation results to 'NaN'(Not a Number)", this));
} else if (getBigDecimalType(a) == Type.POSITIVE_INFINITY || getBigDecimalType(a) == Type.NEGATIVE_INFINITY ) {
throw new RaiseException(getContext().getCoreLibrary().floatDomainError("Computation results to 'Infinity'", this));
} else {
return divSpecialNormal(frame, a, b, 0);
}
}

@Specialization(guards = {
"!isNormal(a)",
"isNormalRubyBigDecimal(b)" })
public Object divSpecialNormal(VirtualFrame frame, RubyBasicObject a, RubyBasicObject b, int precision) {
return super.divSpecialNormal(frame, a, b, precision);
}

@Specialization(guards = {
"!isNormal(a)",
"isSpecialRubyBigDecimal(b)" })
public Object divSpecialSpecial(VirtualFrame frame, RubyBasicObject a, RubyBasicObject b, NotProvided precision) {
if (getBigDecimalType(b) == Type.NEGATIVE_ZERO) {
throw new RaiseException(getContext().getCoreLibrary().zeroDivisionError(this));
} else if (getBigDecimalType(a) == Type.NAN || getBigDecimalType(b) == Type.NAN) {
throw new RaiseException(getContext().getCoreLibrary().floatDomainError("Computation results to 'NaN'(Not a Number)", this));
} else {
return divSpecialSpecial(frame, a, b, 0);
}
}

@Specialization(guards = {
"!isNormal(a)",
"isSpecialRubyBigDecimal(b)" })
Expand Down

0 comments on commit 40e74c4

Please sign in to comment.