Boost logo

Boost Users :

Subject: Re: [Boost-users] math round() functions: away from 0
From: Hicham Mouline (hicham_at_[hidden])
Date: 2010-04-12 16:37:52


Apologies for the non-text formatting.
Here is the same message in pure text:

Hello,

boost/trunk/libs/math/doc/sf_and_dist/html/math_toolkit/utils/rounding/round.html says that:
      Halfway cases are rounded away from zero, regardless of the current rounding direction.

This I believe is compatible with C99 TC3 and therefore the latest C++1x draft.

However, when I ran this program:

#include <cmath>
#include <iostream>
#include <boost/math/special_functions/round.hpp>
inline double round1(double x)
{
 if (x >= 0.0)
  return std::floor(x + 0.5);
else
   return std::ceil(x - 0.5);
}

inline double round2(double x)
{
 return std::floor(x + 0.5);
}

int main()
{
  std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
  std::cout.precision(1);
  std::cout<< "d floor/ceil.5 floor.5 boostmathround"<<std::endl;
  for (double d=-10.5; d<11; d+=0.5)
    std::cout<< d<<" "<< round1(d)<<" "<<round2(d)<<" "<< boost::math::iround<double>(d)<<std::endl;
  return 0;
}

under g++4.3.x and msvc2008 with trunk, the output for all the negative halves does not seem to be away from 0.
The same for boost::math::round<double>(d)

This stuff most likely depends on the bit pattern, so I investigated further.

I raised the precision of std::cout to 18 decimals.
I then rounded this:
    const double dd = -10.5;
which yielded
dd floor/ceil.5 floor.5 boostmathround
-10.500000000000000000 -11.000000000000000000 -10.000000000000000000 -10

and
  for (double d=-10.6; d<-10.4; d+=0.01)
    std::cout<< d<<" "<< round1(d)<<" "<<round2(d)<<" "<< boost::math::iround(d)<<std::endl;

-10.600000000000000000 -11.000000000000000000 -11.000000000000000000 -11
-10.590000000000000000 -11.000000000000000000 -11.000000000000000000 -11
-10.580000000000000000 -11.000000000000000000 -11.000000000000000000 -11
-10.570000000000000000 -11.000000000000000000 -11.000000000000000000 -11
-10.560000000000000000 -11.000000000000000000 -11.000000000000000000 -11
-10.550000000000001000 -11.000000000000000000 -11.000000000000000000 -11
-10.540000000000001000 -11.000000000000000000 -11.000000000000000000 -11
-10.530000000000001000 -11.000000000000000000 -11.000000000000000000 -11
-10.520000000000001000 -11.000000000000000000 -11.000000000000000000 -11
-10.510000000000002000 -11.000000000000000000 -11.000000000000000000 -11

-10.500000000000002000 -11.000000000000000000 -11.000000000000000000 -11

-10.490000000000002000 -10.000000000000000000 -10.000000000000000000 -10
-10.480000000000002000 -10.000000000000000000 -10.000000000000000000 -10
-10.470000000000002000 -10.000000000000000000 -10.000000000000000000 -10
-10.460000000000003000 -10.000000000000000000 -10.000000000000000000 -10
-10.450000000000003000 -10.000000000000000000 -10.000000000000000000 -10
-10.440000000000003000 -10.000000000000000000 -10.000000000000000000 -10
-10.430000000000003000 -10.000000000000000000 -10.000000000000000000 -10
-10.420000000000003000 -10.000000000000000000 -10.000000000000000000 -10
-10.410000000000004000 -10.000000000000000000 -10.000000000000000000 -10
-10.400000000000004000 -10.000000000000000000 -10.000000000000000000 -10

-10.5 has the exact representation in IEEE754 as the 64bit:
  0000000000000000000000000000000000000000000000001010010000000011
with the bits listed from least significant to most, across all bytes.
It is an _exact_ representation as far as I can tell.

therefore there are no hidden issues, and the boost math round() function should round _away_ from 0, to give -11, shouldn't it?

the above round1() function seems to do the right thing....

Regards,


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net