3

假设我想0.011124325465476454在 MATLAB 中将数字转换为字符串。

如果我打

mat2str(0.011124325465476454,100)

我得到0.011124325465476453了最后一位不同的数字。

如果我打num2str(0.011124325465476454,'%5.25f')

我明白了0.0111243254654764530000000

它用不需要的零填充,并且在最后一位不同(3 应该是 4)。

我需要一种方法将具有随机小数位数的数字转换为它们的精确字符串匹配(不填充零,不修改最终数字)。

有没有这样的方法?

编辑:由于我没有记住 Amro 和 nrz 提供的有关精度的信息,因此我添加了有关该问题的更多附加信息。我实际需要转换的数字来自将它们输出到 txt 文件的 C++ 程序,它们都是 C++double类型。[注意:将数字从 txt 文件输入到 MATLAB 的部分不是由我编码的,实际上我不允许修改它以将数字保留为字符串而不将它们转换为数字。我只能访问此代码的“输出”,这是我要转换的数字]。到目前为止,我还没有得到超过 17 位小数的数字(注意:因此,上面提供的带有 18 位小数的示例并不是很有指示性)。

现在,如果号码有 15 位数字,例如 0.280783055069002

然后num2str(0.280783055069002,'%5.17f')mat2str(0.280783055069002,17)返回

0.28078305506900197

这不是确切的数字(请参阅最后一位数字)。

但如果我打 mat2str(0.280783055069002,15)我得到

0.280783055069002哪个是对的!!!

可能有一百万种方法可以“围绕”问题进行“编码”(例如,创建一个进行转换的例程),但是当我输入一个随机数为小数(但不超过 17);

4

4 回答 4

4

我的HPF工具箱还允许您在 MATLAB 中使用任意精度的数字。

在 MATLAB 中,试试这个:

>> format long g
>> x = 0.280783054
x =
               0.280783054

如您所见,MATLAB 用您输入的数字将其写出来。但是 MATLAB 是如何真正“感受”这个数字的呢?它在内部存储什么?看看 sprintf 怎么说:

>> sprintf('%.60f',x)
ans =
0.280783053999999976380053112734458409249782562255859375000000

这就是 HPF 在尝试从双精度数中提取该数字时所看到的:

>> hpf(x,60)
ans =
0.280783053999999976380053112734458409249782562255859375000000

事实是,几乎所有十进制数在浮点运算中都不能精确地表示为双精度数。(出于显而易见的原因,0.5 或 0.375 是该规则的例外。)

但是,当以 18 位的十进制形式存储时,我们看到 HPF 不需要将数字存储为十进制形式的二进制近似值。

x = hpf('0.280783054',[18 0])
x =
0.280783054

>> x.mantissa
ans =
  2 8 0 7 8 3 0 5 4 0 0 0 0 0 0 0 0 0

尼尔斯不明白的是,十进制数不以十进制形式存储为双精度数。例如 0.1 在内部是什么样子?

>> sprintf('%.60f',0.1)
ans =
0.100000000000000005551115123125782702118158340454101562500000

如您所见,matlab 不会将其存储为 0.1。事实上,matlab 将 0.1 存储为二进制数,这里实际上...

1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + 1/65536 + ...

或者如果你喜欢

2^-4 + 2^-5 + 2^-8 + 2^-9 + 2^-12 + 2^13 + 2^-16 + ...

为了准确地表示 0.1,这将需要无限多个这样的项,因为 0.1 是二进制中的重复数字。MATLAB 停止在 52 位。就像 2/3 = 0.6666666666... 作为小数一样,0.1 仅作为双精度的近似值存储。

这就是为什么您的问题完全与精度和双精度所包含的二进制形式有关。

作为聊天后的最终编辑...

关键是 MATLAB 使用 double 来表示数字。因此,它将接收一个最多 15 位十进制数字的数字,并能够使用正确的格式设置将它们吐出。

>> format long g
>> eps 
ans = 
2.22044604925031e-16

所以例如...

>> x = 1.23456789012345
x =
          1.23456789012345

我们看到 MATLAB 做对了。但是现在在末尾再添加一位数字。

>> x = 1.234567890123456
x =
          1.23456789012346

在它的全部荣耀中,看看 x,就像 MATLAB 看到的那样:

>> sprintf('%.60f',x)
ans =
1.234567890123456024298320699017494916915893554687500000000000

因此,请始终注意任何浮点数的最后一位。MATLAB 会尝试智能地舍入,但 15 位数字就在您安全的边缘。

是否需要使用HP​​F或MP之类的工具来解决这样的问题?不,只要你认识到双重的局限性。然而,提供任意精度的工具使您能够在需要时更加灵活。例如,HPF 在地下室区域提供保护数字的使用和控制。如果您需要它们,它们会在那里保存您需要的数字以免损坏。

于 2012-06-05T23:38:42.407 回答
0

您可以将MATLAB File Exchange 中的 Multiple Precision Toolkit用于任意精度数。浮点数通常没有精确的以 10 为底的表示。

于 2012-06-05T20:12:09.993 回答
0

那是因为您的数字超出了double数字类型的精度(它为您提供了 15 到 17 个有效十进制数字)。在您的情况下,一旦评估文字,它就会四舍五入到最接近的可表示数字。

如果您需要比双精度浮点提供的精度更高的精度,请将数字存储在字符串中,或​​使用任意精度库。例如使用符号工具箱:

sym('0.0111243254654764549999999')
于 2012-06-05T20:29:08.943 回答
0

您无法获得 EXACT 字符串,因为该数字存储在 double 类型,甚至 long double 类型中。存储的数字将比您提供的数字略多或少。

计算机只知道二进制数 0 和 1。您必须知道,一个基数中的数字在其他基数中可能表示不同。例如,数字 1/3,基数 10 产生 0.33333333...(省略号(三个点)表示还有更多数字,这里是数字 3),它将被截断为 0.333333;基数 3 产生 0.10000000,看,不多也不少,确切的数量;基数 2 产生 0.01010101...,因此它可能会在计算机中被截断为 0.01010101,即 85/256,四舍五入小于 1/3,并且下次您获取数字时,它不会与您想要的相同

所以从一开始,你应该将数字存储在字符串而不是浮点类型中,否则会失去精度。

考虑到精度问题,MATLAB 提供了任意精度的符号计算。

于 2012-06-06T05:08:17.563 回答