You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The default rounding mode for Number#round is TIES_EVEN since #10508; it rounds 0.5 to 0.0, rounds 1.5 to 2.0, rounds 2.5 also to 2.0, and rounds 3.5 to 4.0. #11097 added a way to change this default but it was rejected.
There is, however, a closely related concept of a default rounding mode for primitive floating-point operations other than #round, being applied to the mantissa bits rather than the integral part when that operation's result is inexact. This is defined in Section 4.3, "Rounding-direction attributes", of IEEE 754-2008. The C interface for this is fegetround and fesetround, plus the four rounding mode constants:
libLibC
{%if flag?(:win32) %}
FE_TONEAREST=0x00000000FE_UPWARD=0x00000200FE_DOWNWARD=0x00000100FE_TOWARDZERO=0x00000300
{%else%}
FE_TONEAREST=0x00000000FE_UPWARD=0x00000800FE_DOWNWARD=0x00000400FE_TOWARDZERO=0x00000C00
{%end%}
fun fegetround : Intfunfesetround(round : Int) : Intend
{LibC::FE_TONEAREST, LibC::FE_UPWARD, LibC::FE_DOWNWARD, LibC::FE_TOWARDZERO}.each do |round|
LibC.fesetround(round)
x =3.0p [1.0/ x, -1.0/ x]
end
For Crystal to fully conform to IEEE 754, we could expose this functionality as Float.rounding_mode : Number::RoundingMode and .rounding_mode=(Number::RoundingMode). Personally I'm not aware of this part of the standard's relevance in real code.
Note the use of x as a separate variable in the above example. LLVM assumes round-to-nearest and it is technically undefined behavior to simply change the rounding mode like that; it is free to replace 1.0 / 3.0 with the round-to-nearest result as an optimization. Instead, a series of constrained floating-point intrinsics are available. This requires compiler support since the rounding mode is taken as an LLVM metadata node and no Crystal expression evaluates to one.
The text was updated successfully, but these errors were encountered:
For Crystal to fully conform to IEEE 754, we could expose this functionality as Float.rounding_mode : Number::RoundingMode and .rounding_mode=(Number::RoundingMode).
HertzDevil
changed the title
Default rounding mode for floating-point operations
Default rounding mode for primitive floating-point operations
Nov 15, 2024
Updated to clarify this issue is for primitive floats only. Note that neither BigFloat nor BigDecimal claims IEEE 754 conformance (for the former we need #11410)
The default rounding mode for
Number#round
isTIES_EVEN
since #10508; it rounds 0.5 to 0.0, rounds 1.5 to 2.0, rounds 2.5 also to 2.0, and rounds 3.5 to 4.0. #11097 added a way to change this default but it was rejected.There is, however, a closely related concept of a default rounding mode for primitive floating-point operations other than
#round
, being applied to the mantissa bits rather than the integral part when that operation's result is inexact. This is defined in Section 4.3, "Rounding-direction attributes", of IEEE 754-2008. The C interface for this isfegetround
andfesetround
, plus the four rounding mode constants:This prints:
For Crystal to fully conform to IEEE 754, we could expose this functionality as
Float.rounding_mode : Number::RoundingMode
and.rounding_mode=(Number::RoundingMode)
. Personally I'm not aware of this part of the standard's relevance in real code.Note the use of
x
as a separate variable in the above example. LLVM assumes round-to-nearest and it is technically undefined behavior to simply change the rounding mode like that; it is free to replace1.0 / 3.0
with the round-to-nearest result as an optimization. Instead, a series of constrained floating-point intrinsics are available. This requires compiler support since the rounding mode is taken as an LLVM metadata node and no Crystal expression evaluates to one.The text was updated successfully, but these errors were encountered: