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: 62503920b0da
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2245c4faccb9
Choose a head ref
  • 6 commits
  • 6 files changed
  • 1 contributor

Commits on Jul 6, 2017

  1. Copy the full SHA
    430503f View commit details
  2. Copy the full SHA
    4ffed1f View commit details
  3. Copy the full SHA
    a94d1b0 View commit details
  4. Copy the full SHA
    cfbb3fa View commit details
  5. Copy the full SHA
    3dfeb12 View commit details
  6. Copy the full SHA
    2245c4f View commit details
151 changes: 63 additions & 88 deletions core/src/main/java/org/jruby/RubyBignum.java
Original file line number Diff line number Diff line change
@@ -138,6 +138,9 @@ public BigInteger getValue() {
return value;
}

@Override
public int signum() { return value.signum(); }

/* ================
* Utility Methods
* ================
@@ -148,10 +151,8 @@ public BigInteger getValue() {
*
*/
public static RubyInteger bignorm(Ruby runtime, BigInteger bi) {
if (bi.compareTo(LONG_MIN) < 0 || bi.compareTo(LONG_MAX) > 0) {
return newBignum(runtime, bi);
}
return runtime.newFixnum(bi.longValue());
return (bi.compareTo(LONG_MIN) < 0 || bi.compareTo(LONG_MAX) > 0) ?
newBignum(runtime, bi) : runtime.newFixnum(bi.longValue());
}

/** rb_big2long
@@ -257,8 +258,7 @@ public IRubyObject to_s(IRubyObject[] args) {
@JRubyMethod(name = "to_s", alias = "inspect")
@Override
public IRubyObject to_s() {
int base = 10;
return RubyString.newUSASCIIString(getRuntime(), getValue().toString(base));
return RubyString.newUSASCIIString(getRuntime(), getValue().toString(10));
}

@JRubyMethod(name = "to_s")
@@ -278,9 +278,10 @@ public IRubyObject to_s(IRubyObject arg0) {
public IRubyObject coerce(IRubyObject other) {
if (other instanceof RubyFixnum) {
return getRuntime().newArray(newBignum(getRuntime(), ((RubyFixnum) other).getLongValue()), this);
} else if (other instanceof RubyBignum) {
}
if (other instanceof RubyBignum) {
return getRuntime().newArray(newBignum(getRuntime(), ((RubyBignum) other).getValue()), this);
}
}

throw getRuntime().newTypeError("Can't coerce " + other.getMetaClass().getName() + " to Bignum");
}
@@ -299,29 +300,27 @@ public IRubyObject op_uminus() {
@JRubyMethod(name = "+", required = 1)
public IRubyObject op_plus(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return addFixnum(((RubyFixnum)other).getLongValue());
} else if (other instanceof RubyBignum) {
return addBignum(((RubyBignum)other).value);
} else if (other instanceof RubyFloat) {
return addFloat((RubyFloat)other);
return op_plus(context, ((RubyFixnum) other).getLongValue());
}
if (other instanceof RubyBignum) {
return op_plus(context, ((RubyBignum) other).value);
}
if (other instanceof RubyFloat) {
return addFloat((RubyFloat) other);
}
return addOther(context, other);
}

public IRubyObject op_plus(ThreadContext context, long other) {
return addFixnum(other);
}

private IRubyObject addFixnum(long other) {
public final IRubyObject op_plus(ThreadContext context, long other) {
BigInteger result = value.add(BigInteger.valueOf(other));
if (other > 0 && value.signum() > 0) return new RubyBignum(getRuntime(), result);
return bignorm(getRuntime(), result);
if (other > 0 && value.signum() > 0) return new RubyBignum(context.runtime, result);
return bignorm(context.runtime, result);
}

private IRubyObject addBignum(BigInteger other) {
public final IRubyObject op_plus(ThreadContext context, BigInteger other) {
BigInteger result = value.add(other);
if (value.signum() > 0 && other.signum() > 0) return new RubyBignum(getRuntime(), result);
return bignorm(getRuntime(), result);
if (value.signum() > 0 && other.signum() > 0) return new RubyBignum(context.runtime, result);
return bignorm(context.runtime, result);
}

private IRubyObject addFloat(RubyFloat other) {
@@ -338,29 +337,27 @@ private IRubyObject addOther(ThreadContext context, IRubyObject other) {
@JRubyMethod(name = "-", required = 1)
public IRubyObject op_minus(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return subtractFixnum(((RubyFixnum)other).getLongValue());
} else if (other instanceof RubyBignum) {
return subtractBignum(((RubyBignum)other).value);
} else if (other instanceof RubyFloat) {
return op_minus(context, ((RubyFixnum)other).getLongValue());
}
if (other instanceof RubyBignum) {
return op_minus(context, ((RubyBignum)other).value);
}
if (other instanceof RubyFloat) {
return subtractFloat((RubyFloat)other);
}
return subtractOther(context, other);
}

public IRubyObject op_minus(ThreadContext context, long other) {
return subtractFixnum(other);
}

private IRubyObject subtractFixnum(long other) {
public final IRubyObject op_minus(ThreadContext context, long other) {
BigInteger result = value.subtract(BigInteger.valueOf(other));
if (value.signum() < 0 && other > 0) return new RubyBignum(getRuntime(), result);
return bignorm(getRuntime(), result);
if (value.signum() < 0 && other > 0) return new RubyBignum(context.runtime, result);
return bignorm(context.runtime, result);
}

private IRubyObject subtractBignum(BigInteger other) {
public final IRubyObject op_minus(ThreadContext context, BigInteger other) {
BigInteger result = value.subtract(other);
if (value.signum() < 0 && other.signum() > 0) return new RubyBignum(getRuntime(), result);
return bignorm(getRuntime(), result);
if (value.signum() < 0 && other.signum() > 0) return new RubyBignum(context.runtime, result);
return bignorm(context.runtime, result);
}

private IRubyObject subtractFloat(RubyFloat other) {
@@ -376,32 +373,25 @@ private IRubyObject subtractOther(ThreadContext context, IRubyObject other) {
*/
@JRubyMethod(name = "*", required = 1)
public IRubyObject op_mul(ThreadContext context, IRubyObject other) {
Ruby runtime = context.runtime;
if (other instanceof RubyFixnum) {
return bignorm(runtime, value.multiply(fix2big(((RubyFixnum) other))));
return op_mul(context, ((RubyFixnum) other).getLongValue());
}
if (other instanceof RubyBignum) {
return bignorm(runtime, value.multiply(((RubyBignum) other).value));
return bignorm(context.runtime, value.multiply(((RubyBignum) other).value));
}
return opMulOther(context, other);
if (other instanceof RubyFloat) {
return RubyFloat.newFloat(context.runtime, big2dbl(this) * ((RubyFloat) other).getDoubleValue());
}
return coerceBin(context, sites(context).op_times, other);
}

@Deprecated
public final IRubyObject op_mul19(ThreadContext context, IRubyObject other) {
return op_mul(context, other);
}

public IRubyObject op_mul(ThreadContext context, long other) {
Ruby runtime = context.runtime;
BigInteger result = value.multiply(long2big(other));
return result.signum() == 0 ? RubyFixnum.zero(runtime) : new RubyBignum(runtime, result);
}

public IRubyObject opMulOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFloat) {
return RubyFloat.newFloat(getRuntime(), big2dbl(this) * ((RubyFloat) other).getDoubleValue());
}
return coerceBin(context, sites(context).op_times, other);
public final IRubyObject op_mul(ThreadContext context, long other) {
return bignorm(context.runtime, value.multiply(long2big(other)));
}

/**
@@ -438,7 +428,7 @@ private IRubyObject op_divide(ThreadContext context, IRubyObject other, boolean
} else {
result = value.divide(otherValue);
}
return bignorm(getRuntime(), result);
return bignorm(runtime, result);
}

/** rb_big_div
@@ -551,7 +541,7 @@ public IRubyObject quo(ThreadContext context, IRubyObject other) {
if (((RubyNumeric) other).getDoubleValue() == 0) {
throw context.runtime.newZeroDivisionError();
}
return RubyFloat.newFloat(getRuntime(), big2dbl(this) / ((RubyNumeric) other).getDoubleValue());
return RubyFloat.newFloat(context.runtime, big2dbl(this) / ((RubyNumeric) other).getDoubleValue());
} else {
return coerceBin(context, sites(context).quo, other);
}
@@ -569,36 +559,20 @@ public final IRubyObject quo19(ThreadContext context, IRubyObject other) {
public IRubyObject op_pow(ThreadContext context, IRubyObject other) {
Ruby runtime = context.runtime;
if (other == RubyFixnum.zero(runtime)) return RubyFixnum.one(runtime);
double d;
final double d;
if (other instanceof RubyFixnum) {
RubyFixnum fix = (RubyFixnum) other;
long fixValue = fix.getLongValue();

if (fixValue < 0) {
return RubyRational.newRationalRaw(runtime, this).callMethod(context, "**", other);
}
// MRI issuses warning here on (RBIGNUM(x)->len * SIZEOF_BDIGITS * yy > 1024*1024)
if (((value.bitLength() + 7) / 8) * 4 * Math.abs(fixValue) > 1024 * 1024) {
getRuntime().getWarnings().warn(ID.MAY_BE_TOO_BIG, "in a**b, b may be too big");
}
if (fixValue >= 0) {
return bignorm(runtime, value.pow((int) fixValue)); // num2int is also implemented
} else {
return RubyFloat.newFloat(runtime, Math.pow(big2dbl(this), (double)fixValue));
}
return op_pow(context, ((RubyFixnum) other).getLongValue());
} else if (other instanceof RubyBignum) {
d = ((RubyBignum) other).getDoubleValue();
getRuntime().getWarnings().warn(ID.MAY_BE_TOO_BIG, "in a**b, b may be too big");
context.runtime.getWarnings().warn(ID.MAY_BE_TOO_BIG, "in a**b, b may be too big");
} else if (other instanceof RubyFloat) {
d = ((RubyFloat) other).getDoubleValue();
if (this.compareTo(RubyFixnum.zero(runtime)) == -1
&& d != Math.round(d)) {
RubyComplex complex = RubyComplex.newComplexRaw(getRuntime(), this);
if (compareTo(RubyFixnum.zero(runtime)) == -1 && d != Math.round(d)) {
RubyComplex complex = RubyComplex.newComplexRaw(context.runtime, this);
return sites(context).op_exp.call(context, complex, complex, other);
}
} else {
return coerceBin(context, sites(context).op_exp, other);

}
double pow = Math.pow(big2dbl(this), d);
if (Double.isInfinite(pow)) {
@@ -607,20 +581,21 @@ public IRubyObject op_pow(ThreadContext context, IRubyObject other) {
return RubyNumeric.dbl2num(runtime, pow);
}

public IRubyObject op_pow(final ThreadContext context, final long other) {
warnIfPowExponentTooBig(context, other);

public final IRubyObject op_pow(final ThreadContext context, final long other) {
if (other >= 0) {
if ( other <= Integer.MAX_VALUE ) { // only have BigInteger#pow(int)
if (other <= Integer.MAX_VALUE) { // only have BigInteger#pow(int)
return bignorm(context.runtime, value.pow((int) other)); // num2int is also implemented
}
warnIfPowExponentTooBig(context, other);
return RubyFloat.newFloat(context.runtime, Math.pow(big2dbl(this), (double) other));
}
return RubyFloat.newFloat(context.runtime, Math.pow(big2dbl(this), (double) other));
// (other < 0)
return RubyRational.newRationalRaw(context.runtime, this).callMethod(context, "**", RubyFixnum.newFixnum(context.runtime, other));
}

private void warnIfPowExponentTooBig(final ThreadContext context, final double other) {
private void warnIfPowExponentTooBig(final ThreadContext context, final long other) {
// MRI issuses warning here on (RBIGNUM(x)->len * SIZEOF_BDIGITS * yy > 1024*1024)
if ( ((value.bitLength() + 7) / 8) * 4 * Math.abs(other) > 1024 * 1024 ) {
if ( ((value.bitLength() + 7) / 8) * 4 * Math.abs((double) other) > 1024 * 1024 ) {
context.runtime.getWarnings().warn(ID.MAY_BE_TOO_BIG, "in a**b, b may be too big");
}
}
@@ -636,9 +611,9 @@ public IRubyObject op_pow19(ThreadContext context, IRubyObject other) {
@JRubyMethod(name = "&", required = 1)
public IRubyObject op_and(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return bignorm(getRuntime(), value.and(((RubyBignum) other).value));
return bignorm(context.runtime, value.and(((RubyBignum) other).value));
} else if (other instanceof RubyFixnum) {
return bignorm(getRuntime(), value.and(fix2big((RubyFixnum)other)));
return bignorm(context.runtime, value.and(fix2big((RubyFixnum)other)));
}
return coerceBit(context, sites(context).op_and, other);
}
@@ -797,16 +772,16 @@ public IRubyObject op_cmp(ThreadContext context, IRubyObject other) {
} else if (other instanceof RubyFloat) {
RubyFloat flt = (RubyFloat)other;
if (flt.infinite_p().isTrue()) {
if (flt.getDoubleValue() > 0.0) return RubyFixnum.minus_one(getRuntime());
return RubyFixnum.one(getRuntime());
if (flt.getDoubleValue() > 0.0) return RubyFixnum.minus_one(context.runtime);
return RubyFixnum.one(context.runtime);
}
return dbl_cmp(getRuntime(), big2dbl(this), flt.getDoubleValue());
return dbl_cmp(context.runtime, big2dbl(this), flt.getDoubleValue());
} else {
return coerceCmp(context, sites(context).op_cmp, other);
}

// wow, the only time we can use the java protocol ;)
return RubyFixnum.newFixnum(getRuntime(), value.compareTo(otherValue));
return RubyFixnum.newFixnum(context.runtime, value.compareTo(otherValue));
}

/** rb_big_eq
3 changes: 3 additions & 0 deletions core/src/main/java/org/jruby/RubyFixnum.java
Original file line number Diff line number Diff line change
@@ -199,6 +199,9 @@ public BigInteger getBigIntegerValue() {
return BigInteger.valueOf(value);
}

@Override
public int signum() { return Long.signum(value); }

public static RubyFixnum newFixnum(Ruby runtime, long value) {
if (USE_CACHE && isInCacheRange(value)) {
return cachedFixnum(runtime, value);
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/RubyInteger.java
Original file line number Diff line number Diff line change
@@ -110,6 +110,8 @@ protected RubyFloat toFloat() {
return RubyFloat.newFloat(getRuntime(), getDoubleValue());
}

public int signum() { return getBigIntegerValue().signum(); }

/* ================
* Instance Methods
* ================
29 changes: 8 additions & 21 deletions core/src/main/java/org/jruby/RubyNumeric.java
Original file line number Diff line number Diff line change
@@ -435,38 +435,25 @@ protected final IRubyObject[] getCoerced(ThreadContext context, IRubyObject othe
return coerceResult(runtime, result, true).toJavaArrayMaybeUnsafe();
}

protected IRubyObject callCoerced(ThreadContext context, String method, IRubyObject other, boolean err) {
protected final IRubyObject callCoerced(ThreadContext context, String method, IRubyObject other, boolean err) {
IRubyObject[] args = getCoerced(context, other, err);
if (args == null) {
return context.nil;
}
if (args == null) return context.nil;
return args[0].callMethod(context, method, args[1]);
}

public IRubyObject callCoerced(ThreadContext context, String method, IRubyObject other) {
IRubyObject[] args = getCoerced(context, other, false);
if (args == null) {
return context.nil;
}
return args[0].callMethod(context, method, args[1]);
public final IRubyObject callCoerced(ThreadContext context, String method, IRubyObject other) {
return callCoerced(context, method, other, false);
}

protected IRubyObject callCoerced(ThreadContext context, CallSite site, IRubyObject other, boolean err) {
protected final IRubyObject callCoerced(ThreadContext context, CallSite site, IRubyObject other, boolean err) {
IRubyObject[] args = getCoerced(context, other, err);
if (args == null) {
return context.nil;
}
if (args == null) return context.nil;
IRubyObject car = args[0];
return site.call(context, car, car, args[1]);
}

public IRubyObject callCoerced(ThreadContext context, CallSite site, IRubyObject other) {
IRubyObject[] args = getCoerced(context, other, false);
if (args == null) {
return context.nil;
}
IRubyObject car = args[0];
return site.call(context, car, car, args[1]);
public final IRubyObject callCoerced(ThreadContext context, CallSite site, IRubyObject other) {
return callCoerced(context, site, other, false);
}

// beneath are rewritten coercions that reflect MRI logic, the aboves are used only by RubyBigDecimal
Loading