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.