THE FOLD / GLITCH / HEISENBUG / THE SHIFT BY WIDTH
THE SHIFT BY WIDTH
two machines, two answers, neither wrong
1 WHAT IT IS · WHAT IT DOES · FACT OR FICTION
Shift a 32-bit value left by 32 places and every bit should fall off the end. The answer is zero. It is not zero on x86, it is not zero on ARM either, and the two disagree.
LIT verified live. over shift counts 0 to 63, the value produced agrees with the mathematical
LIT verified live. over shift counts 0 to 63, the value produced agrees with the mathematical
2k truncated to 32 bits in exactly 32 cases and disagrees in the other 32. The disagreement is not noise: 1 << 32 gives 1, 1 << 33 gives 2, 1 << 64 gives 1 — the shift count is being taken modulo 32 and the value never moves at all. x86 masks the count to five bits and returns 1; ARM saturates the count and returns 0. Same expression, same width, two answers, neither of them wrong.2 HOW IT WAS WEAVED · AI + HUMAN
The C standard leaves a shift by more than the width undefined; x86’s five-bit masking and ARM’s saturating behaviour are documented in both architecture manuals.
AVAN (AI) ran this rather than describing it, because the demonstration is available directly: JavaScript specifies
AVAN (AI) ran this rather than describing it, because the demonstration is available directly: JavaScript specifies
<< to mask the count to five bits, so 1<<32 === 1 is a fact you can watch, and it is the same masking the C program inherits from the instruction. The 32 of 64 is the honest framing — half of all shift counts in the range return a number that is not the value being asked for, and none of them raise anything.3 ONE DIMENSION
Half of all shift counts return the wrong power of two.
4 TWO DIMENSIONS · INTERACTIVE
Turn the count past the width and watch the value come back.
5 THREE DIMENSIONS + AVAN’S INVERSE
The green forward object.
AVAN’s addition (the inverse-companion): the forward reading is that shifting past the width is undefined, so do not. The inverse is that the undefinedness is downstream of a hardware disagreement, not of a lack of thought. The committee did not fail to decide; two architectures had already decided differently, and any definition would have made one of them slow. Read backwards, a large part of undefined behaviour is a fossil of a hardware argument — the specification is silent exactly where the machines were not unanimous, and the cost of that silence lands on a programmer who never attended the argument.
LIT over shift counts 0 to 63 the value produced agrees with the mathematical 2^k truncated to 32 bits in exactly 32 cases and disagrees in the other 32, and the disagreement is not noise: 1 << 32 gives 1, 1 << 33 gives 2, 1 << 64 gives 1, because the count is taken modulo 32 and the value never moves - x86 masks the count to five bits and returns 1 while ARM saturates the count and returns 0, same expression, same width, two answers
FIG The C standard leaves a shift by more than the width undefined; x86's five-bit masking and ARM's saturating behaviour are documented in both architecture manuals. AVAN ran it rather than describing it, because the demonstration is directly available: JavaScript specifies << to mask the count to five bits, so 1<<32 === 1 is a fact you can watch, and it is the same masking a C program inherits from the instruction. Half of all shift counts in the range return a number that is not the value asked for, and none of them raise anything.
FIG The C standard leaves a shift by more than the width undefined; x86's five-bit masking and ARM's saturating behaviour are documented in both architecture manuals. AVAN ran it rather than describing it, because the demonstration is directly available: JavaScript specifies << to mask the count to five bits, so 1<<32 === 1 is a fact you can watch, and it is the same masking a C program inherits from the instruction. Half of all shift counts in the range return a number that is not the value asked for, and none of them raise anything.
◆ sealed .dlw.fold → folded to ROOT_0 · a sphere of HEISENBUG · David Lee Wise (ROOT0), with AVAN