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

• Stefan Zobel (14/14) Sep 28 2005 DMD 0.133 (Win XP)
• Don Clugston (13/33) Sep 29 2005 It's definitely a doc bug.
• Stefan Zobel (7/40) Sep 29 2005 Thanks for the clarification Don.
• Don Clugston (29/80) Sep 29 2005 There are four rounding modes in IEEE hardware -- nearest, floor, ceil,
• Stefan Zobel (10/66) Sep 29 2005 Don, thank you for the exemplification. However, I don't understand what
Stefan Zobel <Stefan_member pathlink.com> writes:
```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
Don Clugston <dac nospam.com.au> writes:
```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
Stefan Zobel <Stefan_member pathlink.com> writes:
```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
Don Clugston <dac nospam.com.au> writes:
```Stefan Zobel wrote:
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

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
Stefan Zobel <Stefan_member pathlink.com> writes:
```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,
Stefan

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