Re: Using Equal with Real Numbers

*To*: mathgroup at smc.vnet.net*Subject*: [mg123187] Re: Using Equal with Real Numbers*From*: A Retey <awnl at gmx-topmail.de>*Date*: Fri, 25 Nov 2011 04:59:02 -0500 (EST)*Delivered-to*: l-mathgroup@mail-archive0.wolfram.com*References*: <jalb8i$s6h$1@smc.vnet.net>

Hi, > Using statements like x1=x2, with real numbers is problematic in > most programming languages. Actually a single = is Set in Mathematica, what you are talking about is ==, which is Equal or === which is SameQ. > Below I briefly discuss an example with Mathematica and then show the > rather truculent solution that I've come up with. > I would love to hear your comments on this and perhaps other (likely > better) solutions. > > 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. > > 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. That's not exactly true, since == will recognize the two to be equal: Range[0, 1, 0.1][[8]] == 0.7 and even SameQ considers Real numbers to be equal if they only differ in their last binary digit (see the documentation of SameQ): Range[0, 1, 0.1][[8]] === 0.7 so the problem is not Equal or even SameQ, but the pattern matcher that MemberQ actually usesimplicitly. The pattern matcher will obviously consider numbers with different binary representation to be different and that doesn't even make use of == or ===. > Here is my solution: > > range[xi_, xf_, df_] := N@Rationalize@Range[xi, xf, df] > > That is, I redefine the range function. It first rationalizes the > entries and then transform them into numeric quantities. Not only is > this crude, but is likely quite slow for long lists. Notwithstanding, it > does solve the problem in the previous example: > > In[190]:= list2 = range[0, 1, 0.1] > Out[190]= {0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.} > > In[191]:= list2 // InputForm > Out[191]//InputForm= {0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, > 1.} > > In[201]:= {MemberQ[list2, 0.6], MemberQ[list2, 0.7]} > Out[201]= {True, True} I don't think that it is a very useful approach to change the actual data when all you want is a different comparison operation. What I would do is something like: list = Range[0, 1, 0.1]; MemberQ[list, _?(# == 0.7 &)] or maybe even: MemberQ[list, _?(Abs[#-0.7]<10^-6 &)] with a maximal acceptable difference appropriate to the problem at hand. If you are wondering about the complicated patterns I suggest to learn about Mathematica's pattern matching. Without a proper understanding of pattern matching you will find Mathematica to be full of surprises and by far not as helpful as it could be... hth, albert