Most Commodore BASIC interpreters have a bug in the floating point multiply routine. The bug can be demonstrated with the following BASIC program:
10 X = 1 + 255/2↑31 20 PRINT X * 1 - X 30 PRINT 1 * X - X
Only BASIC 7.0 produces the correct output:
This bug is not due to the roundoff error intrinsic to floating point arithmetic, because multiplying by 1 does not introduce rounding.
Cause of the bug[edit | edit source]
The 6502 does not have a multiply instruction. The floating point multiply must be done in software, entirely from adds, subtracts and shifts. The routine MLTPLY, located in the C64 BASIC at $BA59, performs part of the floating point multiply. It multiplies the mantissa in the "ARG" area ($69-$6E, also called floating point accumulator 2) by the byte in the A register and adds the product to the scratch area at $26-$29, spilling overflow bits into $70 so the final product can be rounded. The byte in A is derived from the floating point accumulator, which is the second operand in a BASIC multiply expression.
MLTPLY has an optimization for speed. If the byte in the A register is zero, it will bypass its multiply loop and jump instead to MULSHF ($B983). MULSHF is not exclusive to the multiply routine; it is shared with the add routine, which uses a shift to equalize the exponents of the addends. MULSHF entered from the multiply is always supposed to have A equal to zero, and shift by exactly eight bits. But it uses the ADC instruction carelessly, not making sure that the carry flag is in the proper state, and so it can sometimes shift by nine bits.
A patch[edit | edit source]
The C64 BASIC can be patched to remove the bug, implementing the BASIC 7.0 fix, by changing the following bytes. The bytes at offset $1A40 in the ROM image read as follows:
00001a40: 59ba a565 2059 baa5 6420 59ba a563 2059 Y..e Y..d Y..c Y
To patch the bug, change the first and last instances of $59 to $5E:
00001a40: 5eba a565 2059 baa5 6420 59ba a563 205e Y..e Y..d Y..c Y