【问题标题】:Conversion of numeric to string in MATLAB在 MATLAB 中将数字转换为字符串
【发布时间】:2012-06-09 20:58:01
【问题描述】:

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

如果我打了

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 正确!!!

可能有一百万种方法可以“围绕”问题“编写代码”(例如,创建一个进行转换的例程),但是当我输入一个数字时,没有什么方法可以使用标准的内置 MATLAB 获得理想的结果随机小数位数(但不超过 17);

【问题讨论】:

    标签: string matlab floating-point number-formatting


    【解决方案1】:

    你不能得到 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 提供了任意精度的符号计算。

    【讨论】:

      【解决方案2】:

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

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

      sym('0.0111243254654764549999999')
      

      【讨论】:

        【解决方案3】:

        我的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
        

        niels 不理解的是十进制数不以十进制形式存储为双精度数。例如 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 仅存储为双精度的近似值。

        这就是为什么你的问题完全是关于精度和 double 所包含的二进制形式的原因。

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

        关键是 MATLAB 使用双精度来表示数字。因此,它将接收一个最多 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 在地下室区域提供保护数字的使用和控制。如果您需要它们,它们会在那里保存您需要的数字以免损坏。

        【讨论】:

        • @niels - 但是如果不使用可以让您以更高精度工作的工具,您根本无法达到您要求的精度。同样,您需要认识到使用浮点数字形式(这是双精度数)总是会使最低有效数字处于危险之中。像 HPF 这样的形式的另一个优点是它是十进制的。所以数字以十进制形式存储,而不是二进制形式。
        • @niels - 是的,这完全是关于精度和数字作为二进制数存储为双精度数的方式。除非您了解 0.280783054 不能完全用二进制浮点数表示,否则您将永远无法解决此问题。
        • MATLAB 默认将所有数字存储为双精度数,因此尾数为 52 个二进制位。如果您使用单来存储数字,那么 x=single(0.280783054);你会得到: sprintf('%.30f',x) ans = 0.280783057212829589843750000000
        • 请注意,根据其 PDF 文档,此工具箱目前实现了加法、乘法、除法,1/x, sqrt(x), 1/sqrt(x), exp(x), ln(x), 2^x, log2(x), sin(x), cos(x), tan(x), arcsin(x), arccos(x), arctan(x), sinh(x), cosh(x), tanh(x), arsinh(x), arcosh(x), artanh(x)。特别要注意的是,它仅将Matlab 的功能的一个子集 扩展到所需的精度。要检查给定的 Matlab 函数是否变得更高精度,您可能需要使用 edit [function] 命令读取其源代码,并检查所有操作是否都在受支持的范围内。
        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-25
          • 2012-11-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多