Let’s consider the OP_MULDIV
primitive:
Word | Value | Hex | Input | Output | Description |
---|---|---|---|---|---|
OP_MULDIV | ??? | 0x?? | a b c | out | a is first multiplied by b then divided by c. The intermediate product CAN be in the INT128 range, while the final result MUST be in the INT64 range. |
We can implement INT32 version as a macro op_muldiv: OP_ROT OP_ROT OP_MUL OP_SWAP OP_DIV
but then we’re limited to INT32 precision for the result. Still, we can use the macro just to demonstrate utility. Consider this example:
Multiply some x
with 0.999998^10
at max precision:
<1000000000> <0xffffff7f> OP_DUP
<999998> <1000000>
OP_2DUP OP_2ROT OP_2ROT op_muldiv OP_2SWAP
OP_2DUP OP_2ROT OP_2ROT op_muldiv OP_2SWAP
OP_2DUP OP_2ROT OP_2ROT op_muldiv OP_2SWAP
OP_2DUP OP_2ROT OP_2ROT op_muldiv OP_2SWAP
OP_2DUP OP_2ROT OP_2ROT op_muldiv OP_2SWAP
OP_2DUP OP_2ROT OP_2ROT op_muldiv OP_2SWAP
OP_2DUP OP_2ROT OP_2ROT op_muldiv OP_2SWAP
OP_2DUP OP_2ROT OP_2ROT op_muldiv OP_2SWAP
OP_2DUP OP_2ROT OP_2ROT op_muldiv OP_2SWAP
op_muldiv
OP_SWAP op_muldiv
Result: 999979999
The above example essentially unrolls an OP_POW
by using the naive method, which could be further optimized by the square & multiply algorithm:
<1000000000> <0xffffff7f> OP_DUP
<999998> <1000000> op_muldiv
OP_DUP OP_2 OP_PICK op_muldiv OP_DUP
OP_DUP OP_3 OP_PICK op_muldiv
OP_DUP OP_3 OP_PICK op_muldiv
OP_2 OP_PICK op_muldiv
OP_SWAP op_muldiv
With bigger VM limits, one could use this as a building block to implement other functions using Taylor series.
I found that Ethereum folks are considering it too:
- Create a new opcode for muldiv - #9 by moodysalem - EIPs - Fellowship of Ethereum Magicians
- EIP-5000: MULDIV instruction - Core EIPs - Fellowship of Ethereum Magicians
and they already have two similar opcodes that may be useful for other purposes: OP_ADDMOD
, OP_MULMOD