## digitalmars.D.learn - std.math.round() - doc bug?

- Stefan Zobel <Stefan_member pathlink.com> Sep 28 2005
- Don Clugston <dac nospam.com.au> Sep 29 2005
- Stefan Zobel <Stefan_member pathlink.com> Sep 29 2005
- Don Clugston <dac nospam.com.au> Sep 29 2005
- Stefan Zobel <Stefan_member pathlink.com> Sep 29 2005

DMD 0.133 (Win XP) The documentation for "real round(real x)" says: # Return the value of x rounded to the nearest integer. # If the fractional part of x is exactly 0.5, # the return value is rounded to the even integer. In reality, it seems to round the "halfway cases" (fractional part = 0.5) away from zero. Considering that round() delegates to std.c.math.roundl() that's not surprising (AFAIK, roundl() is defined to round "away from zero"). It appears that I have to use "real nearbyint(real x)" to achieve the desired "round to the even integer" behavior? I'm by no means an expert in this matter. Can anyone confirm that this is a doc bug? Best regards, Stefan

Sep 28 2005

Stefan Zobel wrote:DMD 0.133 (Win XP) The documentation for "real round(real x)" says: # Return the value of x rounded to the nearest integer. # If the fractional part of x is exactly 0.5, # the return value is rounded to the even integer. In reality, it seems to round the "halfway cases" (fractional part = 0.5) away from zero. Considering that round() delegates to std.c.math.roundl() that's not surprising (AFAIK, roundl() is defined to round "away from zero"). It appears that I have to use "real nearbyint(real x)" to achieve the desired "round to the even integer" behavior? I'm by no means an expert in this matter. Can anyone confirm that this is a doc bug? Best regards, Stefan

It's definitely a doc bug. Here's the behaviour of the existing functions: round() --- rounds away from zero trunc() --- rounds towards zero floor() --- rounds towards negative infinity ceil() --- rounds towards positive infinity nearbyint() --- round to even (use current rounding mode) rint() --- round to even (use current rounding mode) This exactly matches the C99 behaviour. But it seems that there is no way to ensure round-to-even if the current rounding mode is changed. I think that's a deficiency in C that D should rectify. -Don

Sep 29 2005

In article <dhg7cp$1m8d$1 digitaldaemon.com>, Don Clugston says...Stefan Zobel wrote:DMD 0.133 (Win XP) The documentation for "real round(real x)" says: # Return the value of x rounded to the nearest integer. # If the fractional part of x is exactly 0.5, # the return value is rounded to the even integer. In reality, it seems to round the "halfway cases" (fractional part = 0.5) away from zero. Considering that round() delegates to std.c.math.roundl() that's not surprising (AFAIK, roundl() is defined to round "away from zero"). It appears that I have to use "real nearbyint(real x)" to achieve the desired "round to the even integer" behavior? I'm by no means an expert in this matter. Can anyone confirm that this is a doc bug? Best regards, Stefan

It's definitely a doc bug. Here's the behaviour of the existing functions: round() --- rounds away from zero trunc() --- rounds towards zero floor() --- rounds towards negative infinity ceil() --- rounds towards positive infinity nearbyint() --- round to even (use current rounding mode) rint() --- round to even (use current rounding mode) This exactly matches the C99 behaviour. But it seems that there is no way to ensure round-to-even if the current rounding mode is changed. I think that's a deficiency in C that D should rectify. -Don

Thanks for the clarification Don. BTW, how can the current rounding mode be changed? Other rounding modes are "towards negative infinity" and "towards positive infinity" (converting rint() to floor() / ceil()), right? Thanks, Stefan

Sep 29 2005

Stefan Zobel wrote:In article <dhg7cp$1m8d$1 digitaldaemon.com>, Don Clugston says...Stefan Zobel wrote:

It's definitely a doc bug. Here's the behaviour of the existing functions: round() --- rounds away from zero trunc() --- rounds towards zero floor() --- rounds towards negative infinity ceil() --- rounds towards positive infinity nearbyint() --- round to even (use current rounding mode) rint() --- round to even (use current rounding mode) This exactly matches the C99 behaviour. But it seems that there is no way to ensure round-to-even if the current rounding mode is changed. I think that's a deficiency in C that D should rectify. -Don

Thanks for the clarification Don. BTW, how can the current rounding mode be changed? Other rounding modes are "towards negative infinity" and "towards positive infinity" (converting rint() to floor() / ceil()), right? Thanks, Stefan

There are four rounding modes in IEEE hardware -- nearest, floor, ceil, and trunc(). The round() function in C99 ("high school rounding") is not supported by the hardware, so it's significantly slower. I think it's ridiculous that the most accurate mode is not supported by C99. I also note that in D, cast(int)(x) uses trunc(), following the (stupid and slow) C behaviour. float.html describes how to change the rounding mode. It currently says "[blah, blah, blah]". In a post in dm.D yesterday, I asked Walter what his plans are. He doesn't yet have any. In C, depending on the compiler, it's often done in a user-hostile way with _control87(). Less readable and less portable than asm. C99 has fegetround() and fesetround() in fenv.h. A more D-like alternative might be with properties; something like: if (real.rounding != roundfloor) { typeof(real.rounding) oldmode = real.rounding; real.rounding = roundeven; real.rounding = oldmode; } but at present, all properties for built-in types are read-only. I don't know if writable types would be a problem. Rationale: the rounding mode behaves as if it is a static variable which applies to every floating-point type. Ditto for precision. Downside: it applies to every floating point type, including cfloat and idouble, which in D are not derived from real. I haven't worked out how exceptions could work with properties, though. Do you have any opinions/ideas on any of this? -Don.

Sep 29 2005

In article <dhgqgm$2ajg$1 digitaldaemon.com>, Don Clugston says...Stefan Zobel wrote:In article <dhg7cp$1m8d$1 digitaldaemon.com>, Don Clugston says...It's definitely a doc bug. Here's the behaviour of the existing functions: round() --- rounds away from zero trunc() --- rounds towards zero floor() --- rounds towards negative infinity ceil() --- rounds towards positive infinity nearbyint() --- round to even (use current rounding mode) rint() --- round to even (use current rounding mode) This exactly matches the C99 behaviour. But it seems that there is no way to ensure round-to-even if the current rounding mode is changed. I think that's a deficiency in C that D should rectify. -Don

Thanks for the clarification Don. BTW, how can the current rounding mode be changed? Other rounding modes are "towards negative infinity" and "towards positive infinity" (converting rint() to floor() / ceil()), right? Thanks, Stefan

There are four rounding modes in IEEE hardware -- nearest, floor, ceil, and trunc(). The round() function in C99 ("high school rounding") is not supported by the hardware, so it's significantly slower. I think it's ridiculous that the most accurate mode is not supported by C99.

Don, thank you for the exemplification. However, I don't understand what your "most accurate" mode is (nearest?). And slightly OT: Why wouldn't it be supported by C99? I'd assume that nearbyint/rint take advantage of CPU instructions, or are they missing from the C99 standard?I also note that in D, cast(int)(x) uses trunc(), following the (stupid and slow) C behaviour. float.html describes how to change the rounding mode. It currently says "[blah, blah, blah]". In a post in dm.D yesterday, I asked Walter what his plans are. He doesn't yet have any.

Ah, I see.In C, depending on the compiler, it's often done in a user-hostile way with _control87(). Less readable and less portable than asm. C99 has fegetround() and fesetround() in fenv.h. A more D-like alternative might be with properties; something like: if (real.rounding != roundfloor) { typeof(real.rounding) oldmode = real.rounding; real.rounding = roundeven; real.rounding = oldmode; } but at present, all properties for built-in types are read-only. I don't know if writable types would be a problem. Rationale: the rounding mode behaves as if it is a static variable which applies to every floating-point type. Ditto for precision. Downside: it applies to every floating point type, including cfloat and idouble, which in D are not derived from real.

Personally, I'd prefer a library call for that very reason, but that's just me. Best regards, StefanI haven't worked out how exceptions could work with properties, though. Do you have any opinions/ideas on any of this? -Don.

Sep 29 2005