MathGroup Archive 1997

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: floor problems

  • To: mathgroup at smc.vnet.net
  • Subject: [mg8190] Re: floor problems
  • From: Robert Knapp <rknapp>
  • Date: Mon, 18 Aug 1997 23:24:40 -0400
  • Organization: Wolfram Research, Inc.
  • Sender: owner-wri-mathgroup at wolfram.com

Tom wrote:
> 
> Hello Mathematica users.
> 
> I had a very frustrating time trying to debug some work I was doing in
> Mathematica.  I finally pared it down to a problem with the Floor
> function, and I have illustrated my concern below.  I am using M 3.0 and
> a Mac computer.  Does anyone have any advice or could you tell me if I
> am doing something wrong?
> 
> Floor[(.7 67 10)]
> 
> 469
> 
> Floor[(67 10 .7)]
> 
> 468
> 
> Sincerely,
> 
> Tom De Vries

This interesting example is not a problem with the Mathematica Floor
function.  It is actually an artifact of the floating point arithmetic
on your machine (and mine as well).  

The problem boils down to the fact that .7 cannot be exactly represented
as a binary floating point number.  Thus, when the .7 is converted into
a floating point number, that is only an approximation.  When
multiplications are performed, typically rounding must be done and so
errors can be introduced.  Because of this, floating point
multiplication is not exactly associative, so the order in which it is
done can make a difference.  In fact, with Mathematica 3.0 (on a Pentium
running Linux) -- or with a C or FORTRAN program doing the
multiplication, one gets

In[1]:= a = (.7 67 10)
Out[1]= 469.
In[2]:= b = (67 10 .7)
Out[2]= 469.

The default output form is to have values rounded (to six) digits, so in
this case they appear the same.  However

In[3]:= a - b
                  -14
Out[3]= 5.68434 10

There is a nonzero difference between them.  In fact, this difference is
on the order of 

In[4]:= 469.*2^-53
                  -14
Out[4]= 5.20695 10

Actually, you can check the actual difference is 512 2^-53 (this is a
consequence of the way floating point numbers are represented -- a nice
way to look at this is with the Microscope package in Mathematica)

You can see the differences in the digits with RealDigits

In[5]:= RealDigits[a]
 
Out[5]= {{4, 6, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3}
In[6]:= RealDigits[b]
Out[6]= {{4, 6, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}, 3}

Or by specifying base 2, you can see that there is really only one bit
of difference.

In[7]:= RealDigits[a,2]
Out[7]= {{1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
>     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
>     0, 0, 0, 0, 0, 0, 0}, 9}
In[8]:= RealDigits[b,2]
Out[8]= {{1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1,
>     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
>     1, 1, 1, 1, 1, 1, 1}, 9}
 

This one bit, however small, does make a bigger difference in Floor. 
Functions like Floor, Ceiling, and Round have discontinuities and so are
very sensitive to perturbations near the discontinuities.

The best way to avoid such problems is to try to use exact inputs if the
value is critical.  e.g. Floor[7/10 67 10] will get the result you
expect.  I dont know exactly what type of program you had this in, but
if, for example, the .7 came from a loop iterator, it might be better to
use an exact (rational) loop iterator, and use N[] explicitly where you
need numerical approximations.

Rob Knapp
Wolfram Research, Inc.


  • Prev by Date: Solve
  • Next by Date: Re: NDSolve with InterpolatingFunctions
  • Previous by thread: Re: floor problems
  • Next by thread: Re: floor problems