Signed arithmetic implemented by unsigned word-RAM instructions #
The input registers hold the encodings of two signed integers. The routines use only ordinary
unsigned arithmetic, comparisons and branches; no signed operation is added to the machine.
The bounds exclude the final halt; Exec.executes adds exactly one instruction.
Registers left (index 0) and right (index 1) are inputs, result (index 2) is the output,
and indices 3 through 8 are scratch, including two (index 3). Memory and all other registers
are preserved. Code.rename can place the routines in a larger register file.
The source semantics are GenericRAM.Signed.Arithmetic.eval, covering all five operations:
addition, subtraction, multiplication, Euclidean division and Euclidean remainder, including
Lean's total zero-divisor conventions (a / 0 = 0 and a % 0 = a). The common w + 2
allowance covers exact out-of-range sums, differences and minimum/-1 quotients; it is not a
minimal-width claim for results that fit the source range.
Main definitions #
Signed.add,Signed.subtract,Signed.multiply,Signed.divide,Signed.modulo: fixed unsigned instruction blocks.Signed.Frame: preservation of memory, operands and registers outside the workspace.
Main results #
Signed.exec_add,Signed.exec_subtract,Signed.exec_multiply,Signed.exec_divide,Signed.exec_modulo: charged executions with two extra unsigned bits, independent of the operands and source width.
References #
The instruction blocks and their representation are original implementation choices.
First encoded operand.
Instances For
Second encoded operand.
Instances For
Encoded result.
Instances For
Constant two, used to extract magnitudes and signs.
Instances For
Decoded magnitude of the first operand.
Instances For
Decoded magnitude of the second operand.
Instances For
First operand sign, later reused for the result sign.
Instances For
Second operand sign.
Instances For
Constant zero, used to normalize the result.
Instances For
Decode the two input words into four scratch registers in six instructions.
Instances For
Encode a magnitude and sign, setting the sign of zero to zero.
Instances For
Add equal-sign magnitudes, or subtract the smaller opposite-sign magnitude.
Instances For
Combine decoded operands and encode their sum.
Instances For
Add two sign-and-magnitude words, normalizing the sign of zero.
Instances For
Reverse the right sign bit; the result register temporarily holds the constant one.
Instances For
Subtract by reversing the second operand's sign before the addition block. The temporary sign of zero is immaterial and the result is normalized.
Instances For
Multiply the decoded magnitudes and set the product sign.
Instances For
Multiply the magnitudes and compare the signs, normalizing the sign of zero.
Instances For
Compute the Euclidean quotient magnitude and sign from decoded operands.
Instances For
Signed Euclidean division on sign-and-magnitude words, matching Lean's a / 0 = 0
convention and, for b ≠ 0, Lean's Euclidean Int.ediv: the quotient for which a % b lies in
[0, |b|) (rounding toward -∞ when b > 0 and toward +∞ when b < 0).
Instances For
Compute the encoded Euclidean remainder from decoded operands, preserving a % 0 = a.
Instances For
Signed Euclidean remainder on sign-and-magnitude words, matching Lean's a % 0 = a
convention and returning a nonnegative remainder below |b| when b ≠ 0.
Instances For
Signed addition runs within fifteen instructions at unsigned width w + 2.
The result is exact even when the sum does not fit the source signed range.
Signed subtraction runs within seventeen instructions at unsigned width w + 2.
The result is exact even when the difference does not fit the source signed range.
Signed multiplication runs within fourteen instructions at unsigned width w + 2,
provided the mathematical product fits the source signed range. No double-width unsigned
product is needed: the magnitudes' product equals the magnitude of the signed result.
Signed Euclidean division runs within twenty instructions at unsigned width w + 2,
including Lean's a / 0 = 0 convention. The result is exact even at the minimum/-1
signed overflow (-2 ^ (w - 1)) / (-1) = 2 ^ (w - 1), where GenericRAM.Signed.model faults and
the compiled block returns encode (2 ^ (w - 1)) without fault reflection.
Signed Euclidean remainder runs within thirteen instructions at unsigned width w + 2,
including Lean's a % 0 = a convention.