Karp-Rabin string matching in Java
Clearly, I need more experience with numeric programming, because I spent two days wrestling with overflow issues and floating point error


I'd suggest to just avoid it all. Use mod \$2^{32}\$ arithmetic, ignore overflow, forget floating point and forget BigInteger.

I'm afraid, the problem is not the code, but the algorithm. I can see that the Wikipedia really describes all the strange things concerning modular arithmetic, but I'm pretty sure that you took it too literally.

For a rolling hash, all you need is something like

h = BASE_MULTIPLIER * h + inChar + OUT_MULTIPLIER * outChar;


where inChar is the incoming character, BASE_MULTIPLIER is any number co-prime to \$2^{32}\$ (i.e., odd) and OUT_MULTIPLIER is its \$n\$-th power mod \$2^{32}\$, where \$n\$ is the length of the sliding window.



If you insist on using a prime instead of \$2^{32}\$, then you can do it all without BigInteger as long as the prime fits in an int (use long and compute modulus after each operation).

If you're still unsatisfied with the hash function, then there are simple ways to improve it (just ask).



throw new IllegalArgumentException("Pattern longer than text.");


What's illegal here? It's just not there, cf. "x".contains("abc").

throw new IllegalArgumentException("b cannot be larger than " + q);


It can... IIUIC, it's just hashing, so there's no reason to whine because of collisions as long as they're rare.




  How can I make the code more robust?


Don't require to specify the alphabet and similar things. It's not necessary.


  Did I miss any glaring performance traps?


Both % and BigInteger are performance killers.


  Because of the way I implemented the algorithm, supporting general Unicode strings in UCS-2 or UTF-16 would require doing base-65,536 arithmetic.


If you implemented it my way, there'd be no problem.


  There's no hard limit on the size, but larger alphabets mean more BigInteger math.


Do no BigInteger at all.




  Although the current code is Java 7, I plan to switch to Java 8 in the near future


Just don't. If you see something where Java 8 could obviously help a lot, go for it. Otherwise, I wouldn't care. I'm not saying that Java 8 is no big improvement, it's just that sticking with Java 7 or 6 makes your program more usable.