Благодаря недавней записи в официальной группе новостей Александра Распутинова, теперь я выучил две недокументированные функции, которые контролируют допуски Equal
и SameQ
: $EqualTolerance
и $SameQTolerance
.В Mathematica версии 5 и более ранних версиях эти функции находятся в контексте Experimental`
и хорошо документированы: $ EqualTolerance , $ SameQTolerance .Начиная с версии 6, они перемещаются в контекст Internal`
1016 * и становятся недокументированными, но все еще работают и даже имеют встроенные диагностические сообщения, которые появляются, когда кто-то пытается присвоить им недопустимые значения:
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
Ссылаясь на Александра Распутинова:
Internal` $ EqualTolerance ... принимает действительное значение машины, указывающее число допусков десятичных цифр, которые должны быть применены, т.е. Log [2] / Log [В 10] раз меньше младших разрядов, которые один хочет игнорировать.
Таким образом, установка Internal`$EqualTolerance
в ноль заставит Equal
считать числа равными только тогда, когда они идентичны во всех двоичных файлахцифры (не считая 10 * Precision
цифр):
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
Обратите внимание на следующий случай:
In[3]:= Block[{Internal`$EqualTolerance = 0},
1.0000000000000020 == 1.0000000000000021]
RealDigits[1.0000000000000020, 2] === RealDigits[1.0000000000000021, 2]
Out[3]= True
Out[4]= True
В этом случае оба числа имеют MachinePrecision
, что фактически равно
In[5]:= $MachinePrecision
Out[5]= 15.9546
(53*Log[10, 2]
).С такой точностью эти числа идентичны во всех двоичных цифрах:
In[6]:= RealDigits[1.0000000000000020` $MachinePrecision, 2] ===
RealDigits[1.0000000000000021` $MachinePrecision, 2]
Out[6]= True
Увеличение точности до 16 делает их различными числами произвольной точности:
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
Но, к сожалению, Equal
все еще не удаетсяразличайте их:
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}
Таких случаев бесконечно много:
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
Интересно, что иногда RealDigits
возвращает одинаковые цифры, тогда как Order
показывает, что внутренние представления выраженийне идентичны:
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
Но, похоже, что происходит противоположная ситуация:
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