Wolfram mathematica Mathematica中的Put-Get循环总是确定性的吗?

Wolfram mathematica Mathematica中的Put-Get循环总是确定性的吗?,wolfram-mathematica,Wolfram Mathematica,在Mathematica和其他计算机数学系统中一样,数字在内部以二进制形式存储。但是,当使用Put和PutAppend等函数导出它们时,它们会转换为近似小数。当您使用诸如Get之类的函数将它们重新导入时,它们将从这个近似的十进制表示形式恢复为二进制形式 问题是恢复的数字是否总是与原始二进制数字相同,如果不总是,在哪些情况下不相同,差异有多大?我对Put-Get循环(在同一计算机系统上)特别感兴趣 以下两个简单的实验表明,Mathematica中的Put-Get循环可能总是精确地恢复原始数字,即使

在Mathematica和其他计算机数学系统中一样,数字在内部以二进制形式存储。但是,当使用
Put
PutAppend
等函数导出它们时,它们会转换为近似小数。当您使用诸如
Get
之类的函数将它们重新导入时,它们将从这个近似的十进制表示形式恢复为二进制形式

问题是恢复的数字是否总是与原始二进制数字相同,如果不总是,在哪些情况下不相同,差异有多大?我对
Put
-
Get
循环(在同一计算机系统上)特别感兴趣

以下两个简单的实验表明,Mathematica中的
Put
-
Get
循环可能总是精确地恢复原始数字,即使是任意精度的数字:

In[1]:= list=RandomReal[{-10^6,10^6},10000];
Put[list,"test.txt"];
list2=Get["test.txt"];
Order[list,list2]===0
Order[Total@Abs[list-list2],0.]===0

Out[4]= True
Out[5]= True


In[6]:= list=SetPrecision[RandomReal[{-10^6,10^6},10000],50];
Put[list,"test.txt"];
list2=Get["test.txt"];
Order[list,list2]===0
Total@Abs[list-list2]//InputForm

Out[9]= True
Out[10]//InputForm=
0``39.999515496936205
但也许我错过了什么


更新 对于更正确的测试代码,我发现在现实中,这些测试只显示恢复的数字具有相同的二进制
realdights
,但它们的
精度甚至在
Equal
意义上也可能不同。以下是更正确的测试:

test := (Put[list, "test.txt"];
  list2 = Get["test.txt"];
  {Order[list, list2] === 0,
   Order[Total@Abs[list - list2], 0.] === 0,
   Total[Order @@@ RealDigits[Transpose[{list, list2}], 2]],
   Total[Order @@@ Map[Precision, Transpose[{list, list2}], {-1}]],
   Total[1 - Boole[Equal @@@ Map[Precision, Transpose[{list, list2}], {-1}]]]})

In[8]:= list=RandomReal[NormalDistribution[],10000]^1001;
test
Out[9]= {False,True,0,1,3}
In[6]:= list=RandomReal[NormalDistribution[],10000,WorkingPrecision->50]^1001;
test
Out[7]= {False,False,0,-2174,1}

恐怕我不能给出确切的答案。如果查看文本文件,您会看到它存储为类似值的输入形式,包括非机器精度数字的精度指示

假设
Get
使用与
ImportString
ExportString
相同的转换例程,您的测试可以稍微加快一点

Monitor[
 Do[
  i = RandomReal[{$MinMachineNumber, 10 $MinMachineNumber}, 100000];
  If[i =!= 
    ToExpression[ImportString[ExportString[i, "Text"], "List"]], 
   Print[i]], {n, 100}
  ],
 n]

我已经在$MinMachineNumber和$MaxMachineNumber之间的不同范围内对数亿个数字进行了测试,我总是能得到原始数字。当然,这并不是证据,但如果存在,你似乎不太可能看到这是不正确的数字(在这种情况下,差异将非常小,可以忽略不计)。

需要知道的一件重要的事情是,Put[]/Get[]不会保持压缩数组的压缩。您应该签出DumpSave[]。它的速度更快,因为它是一种二进制格式,并且可以压缩数组

您在代码中依赖于
UnsameQ
,它“仍然认为
实数
如果在最后一个二进制数字中不同,则它们是相等的。”
顺序
没有这样的缺点。有关详细信息,请参阅此线程:“.和关于
ExportString
:显示MathKernel在用户的临时目录
%TEMP%
中创建了一个临时文件,输出为
ExportString[i,“Text”]
。因此,在这种情况下,使用
ExportString
而不是
Put
似乎没有任何好处,因为它们都与文件系统一起工作。@Alexey说得不错。现在我已经计时了,Put/Get的速度似乎是ImportString/ExportString的两倍。我认为它们可以在内存中工作,因此速度更快。我知道
DumpSave
,但我对以人类可读的格式导出表达式感兴趣。我对
Put
PutAppend
创建的默认ASCII表示法非常满意。唯一值得关注的原因是这个问题。使用
RandomReal[{-10^6,10^6},10000]
的缺点是生成$minMachineEnumber数量级的概率可以忽略不计。您只测试大数字,而不是小数字。@Sjoerd请查看更新的问题。@Alexey我注意到您现在正在使用
正态分布来获取更多的小数字。然而,获得$MinMachineNumber顺序的概率仍然可以忽略不计:
概率[-\[Epsilon]0},0]
,对于Epsilon=1000*$MinMachineNumber,它是1.77535*10^-305。@Sjoerd您没有注意到随机变量被提升到1001的幂次。请尝试
RandomReal[正态分布[],100]^1001
。您将看到许多数字甚至比
$MinMachineNumber
更小,比
$maxmachineumber
更大。事实上,我错过了这一个。我被纠正了。