Skip to content

Commit

Permalink
Starlark: optimize StarlarkInt.Big comparison to StarlarkInt.Int{32,64}
Browse files Browse the repository at this point in the history
Perform comparison without conversion of smaller integers to
`BigInteger`.  `StarlarkInt.compareTo` does not allocate now.

For this benchmark:

```
def test():
    x = 17 << 77
    for i in range(10):
        print(i)
        for j in range(10000000):
            x > 1

test()
```

```
A: n=27 mean=4.262 std=0.203 se=0.039 min=4.036 med=4.193
B: n=27 mean=4.113 std=0.172 se=0.033 min=3.859 med=4.049
B/A: 0.965 0.941..0.990 (95% conf)
```

Speed up is about 7% when comparing to an integer outside of
`BigInteger` cached range (-16..16).

Finally, `StarlarkInt.Big` to `StarlarkInt.Big` comparison performance
seems to stay the same (within 95% confidence interval after 100
test iterations).
  • Loading branch information
stepancheg committed Dec 6, 2020
1 parent f8e45f4 commit 5dd4d34
Showing 1 changed file with 22 additions and 7 deletions.
29 changes: 22 additions & 7 deletions src/main/java/net/starlark/java/eval/StarlarkInt.java
Original file line number Diff line number Diff line change
Expand Up @@ -436,17 +436,32 @@ public int compareTo(StarlarkInt x) {

/** Returns a value whose signum is equal to x - y. */
public static int compare(StarlarkInt x, StarlarkInt y) {
if (x instanceof Int32 && y instanceof Int32) {
return Integer.compare(((Int32) x).v, ((Int32) y).v);
long xl = 0, yl = 0;
boolean xbig = false, ybig = false;
try {
xl = x.toLongFast();
} catch (Overflow unused) {
xbig = true;
}

try {
return Long.compare(x.toLongFast(), y.toLongFast());
yl = y.toLongFast();
} catch (Overflow unused) {
/* fall through */
ybig = true;
}

// If both arguments are big integers, we invoke BigInteger.compare.
// If neither argument is big integer, we compare longs.
// If only one argument is big integer, it is bigger than other if positive
// and smaller otherwise.
if (xbig && ybig) {
return ((Big) x).v.compareTo(((Big) y).v);
} else if (xbig) {
return ((Big) x).v.signum();
} else if (ybig) {
return -((Big) y).v.signum();
} else {
return Long.compare(xl, yl);
}

return x.toBigInteger().compareTo(y.toBigInteger());
}

/** Returns x + y. */
Expand Down

0 comments on commit 5dd4d34

Please sign in to comment.