Wolfram mathematica 是否有一个“问题”;“正常”;数学中的EqualQ函数?

Wolfram mathematica 是否有一个“问题”;“正常”;数学中的EqualQ函数?,wolfram-mathematica,Wolfram Mathematica,在Equal的文档页面上,我们看到了 机器的近似数 考虑精度或更高 如果它们的最大差异是 最后七位二进制数字(大约 最后两位小数) 以下是示例(32位系统;对于64位系统,在中间添加更多的零): 我想知道Mathematica中是否有一个“正常”模拟的Equal函数不删除最后7个二进制数字?我不知道已经定义了一个运算符。但您可以定义,例如: longEqual[x_, y_] := Block[{$MaxPrecision = 20, $MinPrecision = 20},

Equal
的文档页面上,我们看到了

机器的近似数 考虑精度或更高 如果它们的最大差异是 最后七位二进制数字(大约 最后两位小数)

以下是示例(32位系统;对于64位系统,在中间添加更多的零):


我想知道Mathematica中是否有一个“正常”模拟的
Equal
函数不删除最后7个二进制数字?

我不知道已经定义了一个运算符。但您可以定义,例如:

longEqual[x_, y_] := Block[{$MaxPrecision = 20, $MinPrecision = 20},
                            Equal[x - y, 0.]]  
longEqual[x_, y_] :=
 Block[{
   $MaxPrecision =  Max @@ StringLength /@ ToString /@ {x, y},
   $MinPrecision =  Max @@ StringLength /@ ToString /@ {x, y}},
   Equal[x - y, 0.]]
例如:

longEqual[1.00000000000000223, 1.00000000000000223]
True
longEqual[1.00000000000000223, 1.00000000000000222]
False   
编辑

如果要概括任意位数,可以执行以下操作,例如:

longEqual[x_, y_] := Block[{$MaxPrecision = 20, $MinPrecision = 20},
                            Equal[x - y, 0.]]  
longEqual[x_, y_] :=
 Block[{
   $MaxPrecision =  Max @@ StringLength /@ ToString /@ {x, y},
   $MinPrecision =  Max @@ StringLength /@ ToString /@ {x, y}},
   Equal[x - y, 0.]]
因此,你在评论中的反例同样有效


定义该函数的另一种方法是使用SetPrecision:

MyEqual[a_, b_] := SetPrecision[a, Precision[a] + 3] == SetPrecision[b, Precision[b] + 3]
这似乎在所有情况下都有效,但我仍然想知道是否有内置函数。在这样一个原始的任务中使用高级函数是很难看的

In[12]:= MyEqual[x_, y_] := Order[x, y] == 0

In[13]:= MyEqual[1.0000000000000021, 1.0000000000000022]

Out[13]= False

In[14]:= MyEqual[1.0000000000000021, 1.0000000000000021]

Out[14]= True

此项测试两个对象是否相同,因为1.0000000000000021和1.000000000000002100的精度不同,因此它们不会被视为相同

我提出了一种策略,使用
realdights
来比较数字的实际数字。唯一棘手的是去掉尾随的零

trunc = {Drop[First@#, Plus @@ First /@ {-Dimensions@First@#, 
         Last@Position[First@#, n_?(# != 0 &)]}], Last@#} &@ RealDigits@# &;
exactEqual = SameQ @@ trunc /@ {#1, #2} &;

In[1]  := exactEqual[1.000000000000000000000000000000000000000000000000000111,
                     1.000000000000000000000000000000000000000000000000000111000]
Out[1] := True
In[2]  := exactEqual[1.000000000000000000000000000000000000000000000000000111,
                     1.000000000000000000000000000000000000000000000000000112000]
Out[2] := False
试试这个:

realEqual[a_, b_] := SameQ @@ RealDigits[{a, b}, 2, Automatic]
选择base 2对于确保比较内部表示非常重要

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

我认为你真的需要说明你想要什么。。。没有办法比较在任何情况下都能让每个人满意的近似实数

无论如何,这里还有几个选择:

In[1]:= realEqual[lhs_,rhs_,tol_:$MachineEpsilon] := 0==Chop[lhs-rhs,tol]

In[2]:= Equal[1.0000000000000021,1.0000000000000021]
        realEqual[1.0000000000000021,1.0000000000000021]
Out[2]= True
Out[3]= True

In[4]:= Equal[1.0000000000000022,1.0000000000000021]
        realEqual[1.0000000000000022,1.0000000000000021]
Out[4]= True
Out[5]= False
随着这两个数字的精度越来越高,如果将
tol
设置得足够高,则始终可以区分它们

请注意,减法是以两个数字中最低的精度进行的。您可以通过执行以下操作以更高的精度实现(这似乎有点毫无意义)

maxEqual[lhs_, rhs_] := With[{prec = Max[Precision /@ {lhs, rhs}]}, 
  0 === Chop[SetPrecision[lhs, prec] - SetPrecision[rhs, prec], 10^-prec]]
也许使用最小精度更有意义

minEqual[lhs_, rhs_] := With[{prec = Min[Precision /@ {lhs, rhs}]}, 
  0 === Chop[SetPrecision[lhs, prec] - SetPrecision[rhs, prec], 10^-prec]]
多亏了Oleksandr Rasputinov最近在官方新闻组发表的文章,现在我学到了两个控制
Equal
SameQ
公差的未记录函数:
$EqualTolerance
$SameQTolerance
。在Mathematica版本5和更早版本中,这些函数存在于
实验性的
上下文中,并且有很好的文档记录:。从版本6开始,它们没有文档记录,但仍然有效,甚至在尝试为其分配非法值时会出现内置诊断消息:

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
引用Oleksandr Rasputinov:

内部“$EqualTolerance…”。。。需要 机器实际值,指示 小数位数的公差 这应该适用,即。 Log[2]/Log[10]乘以 希望使用的最低有效位 忽略

这样,将<代码>内部$等值公差设置为零,将强制<代码>相等只在所有二进制数字相同的情况下考虑数字相等(不考虑O-<代码>精度< /代码>数字):

请注意以下情况:

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[5]:= $MachinePrecision
Out[5]= 15.9546
53*日志[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
有趣的是,有时
realdights
返回相同的数字,而
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

SameQ
可以吗?可能是在截断到您想要保留的位数之后。@Simon Try
1.00000000000000000022===1.00000000000000000021
。你会发现它不好(猜测)也许Mathematica没有把最后一个数字看作是默认精度的一个有效数字。你可以用Buttk符号来表示精度足够高,使所有的数字都很重要——1,000000000000000000,22,代码> 100==1,000000000000000000,21,< /代码>100@Alexey-这就是为什么我说你必须截短到您要比较的数字。@Alexey顺便说一句,硬件浮点可以给出不确定的结果,这可能是
=
删除数字的原因,谢谢。但是添加更多的零总是会破坏这种方法:
longEqual[1.\00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\00000000000000000000000000000000000000000000000023,1.00000000000000000000000000000000000000000000000000000000000000000000000000\00000000000000000000000000000000000000000000000022]
如果至少有一个数字以
NumberMark
:longEqual结尾,则它会工作得更好[1.0000000000000 223`,1.0000000000000 222]@Alexey如果你想保持精度,你应该使用1。
55而不是1。
aloneIt仅在精度与数字长度相同时有效,通常情况下并非如此。MyEqual[1.111
3,1.11100001
3]->True.@Alexey Popkov:我不想设置精度,而是想设置一个与真值的可容忍偏差百分比。例如,让我们假设
xT=245
有一个真值,而
xF=250
有一个假值,但我想设置
xT=xF
,因为与真值的偏差百分比只有2%,而想要容忍这种偏差并接受类似等式的显著性检验。我有大量的等式需要容忍,但我不知道如何为我的等式系统设置这种容忍水平。你能帮我解决这个问题吗?谢谢。@TugrulTemel我建议你在上创建一个具体的问题,并详细描述n和w的例子