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