Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a "normal" EqualQ function in Mathematica?

On the documentation page for Equal we read that

Approximate numbers with machine precision or higher are considered equal if they differ in at most their last seven binary digits (roughly their last two decimal digits).

Here are examples (32 bit system; for 64 bit system add some more zeros in the middle):

In[1]:= 1.0000000000000021 == 1.0000000000000022
1.0000000000000021 === 1.0000000000000022

Out[1]= True

Out[2]= True

I'm wondering is there a "normal" analog of the Equal function in Mathematica that does not drop last 7 binary digits?

like image 375
Alexey Popkov Avatar asked Feb 13 '11 11:02

Alexey Popkov


People also ask

What is normal Mathematica?

The normal vector, or simply the "normal" to a curve, is a vector perpendicular to a curve or surface at a given point.

How do I turn off error messages in Mathematica?

To suppress a particular error message for the remainder of the session, click the "More information" icon to the left of the message, choose Turn Off This Message, and click OK: Subsequent evaluations will not produce the message: Copy to clipboard.

How do you ClearAll in Mathematica?

To clear all definitions of quantities you've introduced in a Mathematica session so far, type: ClearAll["Global'*"].

How do you do square roots in Mathematica?

Enter a √ character as sqrt or \[Sqrt], followed by a number: Copy to clipboard.


2 Answers

Thanks to recent post on the official newsgroup by Oleksandr Rasputinov, now I have learned two undocumented functions which control the tolerance of Equal and SameQ: $EqualTolerance and $SameQTolerance. In Mathematica version 5 and earlier these functions live in the Experimental` context and are well documented: $EqualTolerance, $SameQTolerance. Starting from version 6, they are moved to the Internal` context and become undocumented but still work and even have built-in diagnostic messages which appear when one try to assign them illegal values:

In[1]:= Internal`$SameQTolerance = a

During evaluation of In[2]:= Internal`$SameQTolerance::tolset: 
Cannot set Internal`$SameQTolerance to a; value must be a real 
number or +/- Infinity.

Out[1]= a

Citing Oleksandr Rasputinov:

Internal`$EqualTolerance ... takes a machine real value indicating the number of decimal digits' tolerance that should be applied, i.e. Log[2]/Log[10] times the number of least significant bits one wishes to ignore.

In this way, setting Internal`$EqualTolerance to zero will force Equal to consider numbers equal only when they are identical in all binary digits (not considering out-of-Precision digits):

In[2]:= Block[{Internal`$EqualTolerance = 0}, 
           1.0000000000000021 == 1.0000000000000022]
Out[2]= False

In[5]:= Block[{Internal`$EqualTolerance = 0}, 
           1.00000000000000002 == 1.000000000000000029]
        Block[{Internal`$EqualTolerance = 0}, 
           1.000000000000000020 == 1.000000000000000029]
Out[5]= True
Out[6]= False

Note the following case:

In[3]:= Block[{Internal`$EqualTolerance = 0}, 
           1.0000000000000020 == 1.0000000000000021]
        RealDigits[1.0000000000000020, 2] === RealDigits[1.0000000000000021, 2]
Out[3]= True
Out[4]= True

In this case both numbers have MachinePrecision which effectively is

In[5]:= $MachinePrecision
Out[5]= 15.9546

(53*Log[10, 2]). With such precision these numbers are identical in all binary digits:

In[6]:= RealDigits[1.0000000000000020` $MachinePrecision, 2] === 
                   RealDigits[1.0000000000000021` $MachinePrecision, 2]
Out[6]= True

Increasing precision to 16 makes them different arbitrary-precision numbers:

In[7]:= RealDigits[1.0000000000000020`16, 2] === 
              RealDigits[1.0000000000000021`16, 2]
Out[7]= False

In[8]:= Row@First@RealDigits[1.0000000000000020`16,2]
         Row@First@RealDigits[1.0000000000000021`16,2]
Out[9]= 100000000000000000000000000000000000000000000000010010
Out[10]= 100000000000000000000000000000000000000000000000010011

But unfortunately Equal still fails to distinguish them:

In[11]:= Block[{Internal`$EqualTolerance = 0}, 
 {1.00000000000000002`16 == 1.000000000000000021`16, 
  1.00000000000000002`17 == 1.000000000000000021`17, 
  1.00000000000000002`18 == 1.000000000000000021`18}]
Out[11]= {True, True, False}

There is an infinite number of such cases:

In[12]:= Block[{Internal`$EqualTolerance = 0}, 
  Cases[Table[a = SetPrecision[1., n]; 
    b = a + 10^-n; {n, a == b, RealDigits[a, 2] === RealDigits[b, 2], 
     Order[a, b] == 0}, {n, 15, 300}], {_, True, False, _}]] // Length

Out[12]= 192

Interestingly, sometimes RealDigits returns identical digits while Order shows that internal representations of expressions are not identical:

In[13]:= Block[{Internal`$EqualTolerance = 0}, 
  Cases[Table[a = SetPrecision[1., n]; 
    b = a + 10^-n; {n, a == b, RealDigits[a, 2] === RealDigits[b, 2], 
     Order[a, b] == 0}, {n, 15, 300}], {_, _, True, False}]] // Length

Out[13]= 64

But it seems that opposite situation newer happens:

In[14]:= 
Block[{Internal`$EqualTolerance = 0}, 
  Cases[Table[a = SetPrecision[1., n]; 
    b = a + 10^-n; {n, a == b, RealDigits[a, 2] === RealDigits[b, 2], 
     Order[a, b] == 0}, {n, 15, 3000}], {_, _, False, True}]] // Length

Out[14]= 0
like image 60
Alexey Popkov Avatar answered Sep 21 '22 20:09

Alexey Popkov


Try this:

realEqual[a_, b_] := SameQ @@ RealDigits[{a, b}, 2, Automatic]

The choice of base 2 is crucial to ensure that you are comparing the internal representations.

In[54]:= realEqual[1.0000000000000021, 1.0000000000000021]
Out[54]= True

In[55]:= realEqual[1.0000000000000021, 1.0000000000000022]
Out[55]= False

In[56]:= realEqual[
           1.000000000000000000000000000000000000000000000000000000000000000022
         , 1.000000000000000000000000000000000000000000000000000000000000000023
         ]
Out[56]= False
like image 32
WReach Avatar answered Sep 23 '22 20:09

WReach