Rounding Modes For Floating Operations

At the moment there is no way to specify specific rounding floating pointing operations.

since we are able to specify extra symbols along with standard operator for some operations like Wrapping Addition (+%), Saturating Addition (+|), and etc.

In the same way, can we add some additional symbols to the language to specify rounding modes for floating point operations. like +{some symbol} for the followings:

  • Round to Nearest, ties to Even.
  • Round towards Zero.
  • Round Down (towards −∞).
  • Round Up (towards +∞).
  • Round to Nearest, ties to Max Magnitude.

Also I want to highlight a bug (issue #36420) in here. @min and @max outputs non deterministically for -0e0 and 0e0 as some case output correctly (-0e0 is strictly less than 0e0) but in many just outputs the second argument.

Just in case you’re not aware, there was some discussion about this recently on the Zulip. I don’t know whether a decision was reached.

I think I found it. This? floating point environment language support proposal

also relevant message in codeberg

I cannot understand what are the expectations for rounding of binary floating point numbers. —It does not make sense. For example, what is ‘ties’? 0 or 1?
Of course it matters if we use decimal floating point numbers, where ‘ties’ is 5.
But zig currently does not support decimal floating point numbers.

The rounding mode is for rounding intermediate results that are more precise than what can be represented as a floating-point data type of a given precision.

Let’s use f16 (half precision) as an example because it’s smaller and thus easier to break down in text.

Take the value -300.0, or -0x1.2c0p+8 in hexadecimal-significand form. The value is computed via −1−1 × 28 × 1.2C016 = −300.0

f16 has a significand precision of 11 bits, so in a (fictional) “binary-significand” form, you could write this as -0b1.0010110000p+8. The least significant digit is 0 and thus even.

The two nearest representable values are -0b1.0010101111p+8 = -299.75 and -0b1.0010110001p+8 = -300.25. Both of these numbers’ least significant digits are 1 and thus odd.

If you compute -200.0 - 100.125, the result -300.125 cannot be exactly represented and must thus be rounded to either -300.0 or -300.25. Which rounded value is chosen depends on the rounding mode. For “ties to even”, the rounded value is -300.0 because it’s the one that has an even least significant digit in binary-significand form.

Another even simpler way to put it is that the bitwise representation of the encoded value -300, i.e. 0b1101110010110000, has an even least significant digit.

I’d recommend playing around with https://float.exposed/ to get an intuitive feel for how floating-point numbers work and why changing the exponent affects the precision of values that can be stored.


Edit: To clarify, the “tie” is when you have e.g. 0b1.0101 and you need to round it to 4 digits. 0b1.0101 lies exactly between 0b1.010 and 0b1.011. Just like how 5.0505 lies exactly between 5.050 and 5.051.

8 Likes

Thank you very much for the explanation. Yes, this make sense now.