Making Floating-Point Deterministic: Extending WebAssembly with Explicit Rounding Instructions
Short summary: In this series, I extend the official WebAssembly reference interpreter by implementing a custom instruction. This requires modifying the runtime, adding validation logic, and writing spec-compliant test cases.
Why 1.79e308 + 1.79e308 = 1.79e308?
When I started learning computer science, I thought a computer was a fancy calculator that could add, subtract, multiply, and divide (including matrices).
My understanding changed when a friend showed me an interesting example. Open the WebAssembly interpreter and type :
(assert_return (invoke "f64.add_floor" (f64.const 1.7976931348623157e308) (f64.const 1.7976931348623157e308)) (f64.const 1.7976931348623157e308))
Strange, isn't it? Since when did 1.79... + 1.79... = 1.79... ? So a + a = a? That doesn't make sense, does it?
But that's not all, look now. 'NaN' is a way to show that a number isn't a number. The idea is logical. The authors wanted something to show, for example, the result of division by 0. And what happens when we add two 'NaN's? It's not even a number, but interpreters of various languages allow it!
We won't even get into Nany signaling, or quiet...
Why does this happen? It's tempting to say that's what the IEEE754 standard says. But why does the standard allow something that looks like an error?
I then began to wonder if a computer even performs the same kind of addition we learned in school. The more I read the specification, the more the words "addition," "subtraction," or "multiplication" seemed misleading.
To a processor, a number is just a sequence of bits
A computer doesn't understand the word "addition." It understands that when two numbers are presented with an "add" instruction, a specific series of transformations must be performed, which don't always produce the expected result.
I understood something that was useful to me while working on the WebAssembly interpreter: that floating-point operations aren't described by mathematics, but by the standard. And the standard doesn't say "add these numbers." Instead, it tells what bits are to appear on the output for each possible combination of bits on the input.