Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wolfram mathematica 重复和计数中的不稳定性_Wolfram Mathematica_Duplicates_Precision - Fatal编程技术网

Wolfram mathematica 重复和计数中的不稳定性

Wolfram mathematica 重复和计数中的不稳定性,wolfram-mathematica,duplicates,precision,Wolfram Mathematica,Duplicates,Precision,在准备答案的过程中,我发现DeleteDuplicates和Tally两个方面都不稳定(因为没有更好的术语),我不理解 首先考虑: a = {2.2000000000000005, 2.2, 2.1999999999999999}; a // InputForm DeleteDuplicates@a // InputForm Union@a // InputForm Tally@a // InputForm {2.2000000000000006, 2.2, 2.19999999999999

在准备答案的过程中,我发现
DeleteDuplicates
Tally
两个方面都不稳定(因为没有更好的术语),我不理解

首先考虑:

a = {2.2000000000000005, 2.2, 2.1999999999999999};

a // InputForm
DeleteDuplicates@a // InputForm
Union@a // InputForm
Tally@a // InputForm
{2.2000000000000006, 2.2, 2.1999999999999997}
{2.20000000000000006`,1},{2.2,2}}在我看来,依赖任何东西来进行
Tally
DeleteDuplicates
的默认(
SameQ
-like-based)比较函数和数值依赖于实现细节,因为
SameQ
没有一个定义良好的数值语义。您看到的是在其他语言中通常被称为“未定义的行为”。为了得到可靠的结果,我们应该做的是使用

DeleteDuplicates[a,Equal]


对于
Union
(尽管我不会使用
Union
,因为显式测试会导致它的二次复杂性)。OTOH,如果你想了解内部实施细节,因为你想利用它们,我只能说,这可能弊大于利,特别是因为这些实现会随着版本的变化而变化,即使假设您对某个特定版本的所有细节都做了正确的处理。

所展示的行为似乎是由于与浮点运算相关的常见问题以及某些应用程序中的一些可疑行为造成的正在讨论的职能

SameQ不是等价关系

第一个SLATE:考虑<代码> SameQ <代码>不是一个等价关系,因为它不是及物的:

In[1]:= $a = {11/5, 2.2000000000000005, 2.2, 2.1999999999999997};

In[2]:= SameQ[$a[[2]], $a[[3]]]
Out[2]= True

In[3]:= SameQ[$a[[3]], $a[[4]]]
Out[3]= True

In[4]:= SameQ[$a[[2]], $a[[4]]]
Out[4]= False                     (* !!! *)
因此,在开始使用其他函数之前,我们就面临着不稳定的行为

这种行为是由于
SameQ
的记录规则,即如果两个实数“在最后一个二进制数字中不同”,则将它们视为“相等”:

请注意,严格来说,
$a[[3]]
$a[[4]]
在最后两个二进制数字中不同,但差异的大小是最低阶的一位

DeleteDuplicates并不真正使用SameQ

下一步,考虑文档说明<代码> DeleDeLePial[[…] /代码>等效于<代码> DeleDeDePialOs[…,SameQ ] < /代码>。嗯,这是严格正确的——但可能不是你所期望的:

In[6]:= DeleteDuplicates[$a] // InputForm
Out[6]//InputForm= {11/5, 2.2000000000000006, 2.2}

In[7]:= DeleteDuplicates[$a, SameQ] // InputForm
Out[7]//InputForm= {11/5, 2.2000000000000006, 2.2}
同样,正如文件所记载的。。。但是这个呢:

In[8]:= DeleteDuplicates[$a, SameQ[#1, #2]&] // InputForm
Out[8]//InputForm= {11/5, 2.2000000000000006, 2.1999999999999997}
当比较函数明显是
SameQ
时,
DeleteDuplicates
似乎通过不同的逻辑分支,而不是行为与
SameQ
相同的函数

理货是。。。困惑

计数
显示类似但不完全相同的不稳定行为:

In[9]:= Tally[$a] // InputForm
Out[9]//InputForm=  {{11/5, 1}, {2.2000000000000006, 1}, {2.2, 2}}

In[10]:= Tally[$a, SameQ] // InputForm
Out[10]//InputForm= {{11/5, 1}, {2.2000000000000006, 1}, {2.2, 2}}

In[11]:= Tally[$a, SameQ[#1, #2]&] // InputForm
Out[11]//InputForm= {{11/5, 1}, {2.2000000000000006, 1}, {2.2000000000000006, 2}}
最后一个数字尤其令人困惑,因为同一数字在列表中出现两次,但计数不同

Equal遇到了类似的问题

现在,回到浮点相等的问题
Equal
SameQ
好一点——但强调“很少”
Equal
查看最后七位二进制数字,而不是最后一位。不过,这并不能解决问题。。。麻烦的情况总是可以找到:

In[12]:= $x1 = 0.19999999999999823;
         $x2 = 0.2;
         $x3 = 0.2000000000000018;

In[15]:= Equal[$x1, $x2]
Out[15]= True

In[16]:= Equal[$x2, $x3]
Out[16]= True

In[17]:= Equal[$x1, $x3]
Out[17]= False             (* Oops *)
这个恶棍揭开了面纱

所有这些讨论的罪魁祸首都是浮点实数格式。用有限格式完全表示任意实数是不可能的。这就是为什么Mathematica强调符号形式,并尽可能长时间地使用符号形式的表达式。如果你发现数字形式是不可避免的,那么你就必须涉入其中,整理所有涉及平等和不平等的角落案例


Poor
SameQ
Equal
DeleteDuplicates
Tally
,他们所有的朋友都没有机会。

离题:到目前为止,没有一次访问这个网站不了解mma的新情况。我想“未定义的行为”是合理的,但不知何故,我期望更多的一致性。我想这就是“未定义”的意思。我想这只是运气,我用了默认的
计数
删除重复项[a,Equal]
似乎也默认为默认值,与
删除重复项[a,Equal[##]和]
@Rojo不一样这很奇怪。听起来像个bug。+1-非常好的讨论,谢谢!从实际的角度来看,我仍然打赌
Equal
将处理比
SameQ
更令人满意的情况。一个更好的定义问题是定义基于某些刚性网格(一组容器)的等价类,如果两个数在相同的“bin”中结束,则考虑两个数相等。这是特别的,但定义明确,对于许多问题来说可能不是那么不合理。@Leonid and Frarach,
Order[#,#2]==0&
是SameQ-and-I-Really-Mean-It-This-Time的最佳选择?@Mr.Wizard我认为,
Order
的使用方式并不能解决@Frarach所讨论的任何类型的问题,这是SameQ的固有特性。两者都是象征性的比较。顺序的意义在于它是一个比较函数,而不是一个等价关系。这是一个更强的条件,例如,
Union
只给出
SameQ
别无选择,只能是二次复杂度(成对比较),而对于
顺序
原则上可以是
n log n
,因为可以使用
顺序
对列表进行排序(在实践中,内置的
Union
n
中始终是二次的,带有显式测试,唉).@Mr.Wizard关于
Order
的文档对此没有提及,但实验表明,
Order
正在对浮点po进行位比较 {11/5, 2.2000000000000006, 2.2} {2.1999999999999997, 2.2, 11/5, 2.2000000000000006} {{11/5, 1}, {2.2000000000000006, 1}, {2.2, 2}}
a = {2.2000000000000005, 2.2, 2.1999999999999999};
a // InputForm
Tally@a // InputForm
{2.2000000000000006, 2.2, 2.1999999999999997} {{2.2000000000000006`, 3}}
a = Developer`ToPackedArray@a;
a // InputForm
Tally@a // InputForm
{2.2000000000000006, 2.2, 2.1999999999999997} {{2.2000000000000006`, 1}, {2.2, 2}}
DeleteDuplicates[a,Equal]
Tally[a,Equal]
In[1]:= $a = {11/5, 2.2000000000000005, 2.2, 2.1999999999999997};

In[2]:= SameQ[$a[[2]], $a[[3]]]
Out[2]= True

In[3]:= SameQ[$a[[3]], $a[[4]]]
Out[3]= True

In[4]:= SameQ[$a[[2]], $a[[4]]]
Out[4]= False                     (* !!! *)
In[5]:= {# // InputForm, Short@RealDigits[#, 2][[1, -10;;]]} & /@ $a[[2;;4]] // TableForm
(* showing only the last ten binary digits for each *)
Out[5]//TableForm= 2.2000000000000006  {0,1,1,0,0,1,1,0,1,1}
                   2.2                 {0,1,1,0,0,1,1,0,1,0}
                   2.1999999999999997  {0,1,1,0,0,1,1,0,0,1}
In[6]:= DeleteDuplicates[$a] // InputForm
Out[6]//InputForm= {11/5, 2.2000000000000006, 2.2}

In[7]:= DeleteDuplicates[$a, SameQ] // InputForm
Out[7]//InputForm= {11/5, 2.2000000000000006, 2.2}
In[8]:= DeleteDuplicates[$a, SameQ[#1, #2]&] // InputForm
Out[8]//InputForm= {11/5, 2.2000000000000006, 2.1999999999999997}
In[9]:= Tally[$a] // InputForm
Out[9]//InputForm=  {{11/5, 1}, {2.2000000000000006, 1}, {2.2, 2}}

In[10]:= Tally[$a, SameQ] // InputForm
Out[10]//InputForm= {{11/5, 1}, {2.2000000000000006, 1}, {2.2, 2}}

In[11]:= Tally[$a, SameQ[#1, #2]&] // InputForm
Out[11]//InputForm= {{11/5, 1}, {2.2000000000000006, 1}, {2.2000000000000006, 2}}
In[12]:= $x1 = 0.19999999999999823;
         $x2 = 0.2;
         $x3 = 0.2000000000000018;

In[15]:= Equal[$x1, $x2]
Out[15]= True

In[16]:= Equal[$x2, $x3]
Out[16]= True

In[17]:= Equal[$x1, $x3]
Out[17]= False             (* Oops *)