I'm working with the Algorand contract code which has a very limited scope of possible operations in their assembly code - e.g., it is not possible to control flow of the code. Basic 64 bit arithmetic operations are available.
What I need to do is to divide two 64-bit segments (as a whole 128-bit number) of a certain 128-bit integer by another 64-bit integer knowing that the result will fit within 64-bit integer. Is it possible without controlling flow of the code and only with 64-bit arithmetics?
I am not familiar with the Algorand language. It is certainly possible to create branch-free code for dividing an 128-bit operand by a 64-bit operand using 64-bit operations throughout. The easiest way to do this is to use long-hand division and multiplication algorithms we all learned in elementary school, but using 232 as the base, not 10. Generally speaking, this requires shifts and logical operations in addition to simple arithmetic, and this is what I assume is available in ISO-C99 code below.
One can use the existing 64-bit division to generate a close estimate of the next quotient "digit" by dividing the leading two "digits" of the dividend by the leading "digit" of the divisor, where "digit" is to be understood base 232. In TAOCP Knuth shows that the error is positive and at most 2, provided the divisor is normalized, that is, its most significant bit is set. We compute the remainder via a back-multiply and subtraction and then can check whether it is negative. If so, we lower the (partial) quotient by one and recompute the remainder.
As branching is not allowed, a mechanism is needed for selecting between two possible conditionally selecting from two operands. This can be done by computing a predicate into an integer which takes the value 0 or 1, and passing that to a 2:1 multiplexer function that multiplies one source operand with the predicate, the other one with the complement of the predicate and adds the results. In the code below this function is called
mux_64().I have tested the division code in function
my_div_128_64()by comparing it to theDIVinstruction of my 64-bit Intel CPU, accessing that instruction via inline assembly. The code was built with the Intel compiler version 13. I have implemented two test modes, one based on purely random operands and the other one is based on simple patterns that are useful for hitting various boundary cases. No mismatches have been found so far. More elaborate tests are possible, but this should be sufficient for a decent "smoke" test.If the programming language is more severely restricted, all of shifts and all logical operations, except those used inside the predicate functions
neq_64(),ltu_64(), andgeu_64(), can be replaced with arithmetic. Examplary ISO-C99 code is shown below. There may be programming language specific ways to implement these predicates without the use of logical operations.