On 11/24/11 at 6:53 AM, gtlandi at gmail.com (Gabriel Landi) wrote:
>Consider:
>In[187]:= list1 = Range[0, 1, 0.1] Out[187]= {0., 0.1, 0.2, 0.3,
>0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.}
>Using InputForm we see that:
>In[188]:= list1 // InputForm
>Out[188]//InputForm={0., 0.1, 0.2, 0.30000000000000004, 0.4, 0.5,
>0.6000000000000001, 0.7000000000000001, 0.8, 0.9, 1.}
>That is, 0.3, 0.6 and 0.7 have some round-off error.
Actually, only three of these values can be expressed in a
finite number of digits. That is:
In[51]:= FromDigits[First@#, 2] 2^(-Length@First@# + Last@#) & /@
RealDigits[Range[0, 1, .1], 2] - Range[0, 10]/10
Out[51]= {0,1/180143985094819840,1/90071992547409920,1/22517998136852480,1/45035996273704960,0,1/11258999068426240,3/45035996273704960,1/22517998136852480,1/45035996273704960,0}
>Now:
>In[200]:= {MemberQ[list1, 0.6], MemberQ[list1, 0.7]} Out[200] >{True, False}
>(This actually depends on the OS and perhaps other things). The
>point is that he recognizes 0.6 as a member of list1 but not 0.7,
>even though both have the same InputForms. This issue, as you may
>imagine, prohibits one from using functions that implicitly make use
>of =, when dealing with real numbers.
>Here is my solution:
>range[xi_, xf_, df_] := N@Rationalize@Range[xi, xf, df]
It was somewhat surprising to me this actually worked.
It seems to me a simpler solution would be to use:
MemberQ[Rationalize[list1],6/10]
or
MemberQ[Rationalize[list1], Rationalize[.6]]
I believe the internal algorithm Mathematica uses for Range[xi,
xf, df] is add df to xi and repreat adding df to the sum until
xf is reached. If so, choosing a value for df that cannot be
represented in a finite number of binary digits means there will
be an accumulated error. I recall reading somewhere Mathematica
uses a few extra binary digits beyond the standard number used
for a machine precision value. If so, the accumulated error will
not be a simple monotonic sequence since at each step the sum is
converted to a machine precision value prior to the next sum
being computed. At least the following suggests my hypothesis is
close to correct.
In[59]:= x =
FromDigits[First@#, 2] 2^(-Length@First@# + Last@#) & /@
RealDigits[Range[0, 1, .1], 2] - Range[0, 10]/10;
In[60]:= x/x[[2]]
Out[60]= {0,1,2,8,4,0,16,12,8,4,0}
In any case, the underlying issue is one that is inherent to
using machine precision numbers rather than exact arithmetic.