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 Try1.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.1113,1.11100001
3]->True.@Alexey Popkov:我不想设置精度,而是想设置一个与真值的可容忍偏差百分比。例如,让我们假设xT=245
有一个真值,而xF=250
有一个假值,但我想设置xT=xF
,因为与真值的偏差百分比只有2%,而想要容忍这种偏差并接受类似等式的显著性检验。我有大量的等式需要容忍,但我不知道如何为我的等式系统设置这种容忍水平。你能帮我解决这个问题吗?谢谢。@TugrulTemel我建议你在上创建一个具体的问题,并详细描述n和w的例子