3 ms·
What lookup tables for powers of 31 do you mean? The HashMap implementation internally uses lookup tables (arrays) with sizes that are powers of 2, which might
by tom_mellior 7y ago
What lookup tables for powers of 31 do you mean?
The HashMap implementation internally uses lookup tables (arrays) with sizes that are powers of 2, which might be what you mean? The incoming hash code can happily use all 32 bits of the int type, and its calculation is allowed to overflow and wrap. When indexing into the hash bucket array, HashMap masks off the extra bits that would lead to an index out of bounds exception otherwise.
- hinkley 7y agoLook at the github repository. He's practically turned the hash code calculations inside out to do memoization, and one of the things he's doing is precalculating the hashes and merging them. He's making the observation that ((n * 31 + x) * 31 + y) * 31 + z = 31^3 * n + 31^2 * x + 31 * y + z His code calculates (31^3 * n) + (31^2 * x + 31 * y + z ), memoizing the first and second terms and combining them for each pairing of n, x, y, and z. That's algebra, and of course it holds for all real numbers... if you have infinite precision arithmetic. We do not. We have 32 bit integers, and overflow behaves oddly in some cases. My question is does the overflow behave uniformly for all combinations of those two terms. I thought the answer was 'no', so I'm wondering if he's missing some matches.
- tom_mellior 7y agoThanks, I missed the point that this was related to the GitHub repository. Integer addition and multiplication are associative and commutative, even in the presence of two's complement wraparound. So this transformation is valid. I don't have a source to point you to, though. I'd be interested in one, if anyone has one. (Or just a proof, if it fits here.)
- pzemtsov 7y agoThis is all actually pretty safe. Firstly, Java, unlike C, makes full commitments to the bit-to-bit results of all arithmetic calculations. C only does that for the unsigned calculations, giving a compiler some freedom for the signed case. Java postulates that everything is calculated in binary 2's complememt code. No other arithmetic engines are allowed. Secondly, within this engine, everything is done modulo 2^32, even despite the fact that Java ints are signed. At least, this is so as long as you avoid division. Multiplication of the unsigned numbers produces bit-to-bit the same result as that of unsigned ones. For instance, let's multiply -1 by -1 (FFFFFFFF by FFFFFFFF). It, obviously, produces 1. Now, let's go unsigned: FFFFFFFF times FFFFFFFF is FFFFFFFE00000001, or, in the last 32 bits, 1. So, if in Java you want to perform any computations modulo 2^32, go for it. Just avoid division.