Is there a “normal” EqualQ function in Mathematica?

后端 未结 7 576
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-24 03:49

On the documentation page for Equal we read that

Approximate numbers with machine precision or higher are considered equal if they d

相关标签:
7条回答
  • 2020-12-24 04:39

    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
    
    0 讨论(0)
提交回复
热议问题