-
-
Notifications
You must be signed in to change notification settings - Fork 925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
n ** m
is slow
#3818
Comments
Appears to be because there are so many BigInteger allocations/operations in the Demonstrated by this hack: diff --git a/core/src/main/java/org/jruby/util/Numeric.java b/core/src/main/java/org/jruby/util/Numeric.java
index cab2ebe..087aa32 100644
--- a/core/src/main/java/org/jruby/util/Numeric.java
+++ b/core/src/main/java/org/jruby/util/Numeric.java
@@ -507,6 +507,9 @@ public class Numeric {
y >>= 1;
}
+ if (z * x > z) {
+ z *= x;
+ } else {
BigInteger bigX = BigInteger.valueOf(x);
BigInteger bigXZ = bigX.multiply(bigX);
if (bigXZ.divide(bigX).longValue() != z) {
@@ -515,6 +518,7 @@ public class Numeric {
return v;
}
z = bigXZ.longValue();
+ }
} while(--y != 0);
if (neg) z = -z;
return RubyFixnum.newFixnum(runtime, z); output:
|
Incidentally, I can't provide a proper PR/patch, because I'm totally lost by this logic around the x/y/z values: BigInteger bigX = BigInteger.valueOf(x);
BigInteger bigXZ = bigX.multiply(bigXZ); /* is this right? */
if (bigXZ.divide(bigX).longValue() != z) {
/* .. */
}
z = bigXZ.longValue(); In pseudocode this is: xz = x * x #?
if (xz / x != z) # ?? (x*x)/x==x, no? so this is: if (x != z)
# ...
end
z = xz # z = x*x? I expected z = x*z I can't work out what that Is this the real cause of the slowdown? |
@phluid61 yeah seems like this should be z and not x. Because of that we seem to always going the Bignum algo at that point which will be slow. In MRI, if (MUL_OVERFLOW_FIXNUM_P(x, z)) {
goto bignum;
} So this logic is meant to be a replacement for MRI's overflow check. When I change this to use BigInteger.valueOf(z) we double in speed and avoid going down biginteger path but then we fail one boundary test in ruby/spec. |
Ok I basically ported MRI's overflow check. Numbers...Before:
After:
Compared to MRI 2.3:
|
👍 |
@phluid61 Thanks for bringing this to light. Almost makes me want to generate some microbenches against other numeric operations to see if we have other issues. |
👍 on more numeric benchmarks!
|
Environment
Expected Behavior
**
should have comparable benchmark for Integers as*
Actual Behavior
Benchmarks show
**
is an order of magnitude slower than*
for Integers, andInteger ** Integer
is slower thanFloat ** Integer
test.rb:
MRI:
jruby:
Originally reported here
The text was updated successfully, but these errors were encountered: