【问题标题】:Controlling division precision控制分割精度
【发布时间】:2015-11-17 21:00:01
【问题描述】:

考虑以下简单的划分:

A=8.868;
A/0.1
ans =
  88.679999999999993

由于浮点精度,这会导致一个小错误。有什么办法可以防止这种情况发生吗?基本上我所做的只是将逗号移动一个位置,而不是接近 MATLAB 中允许的最大位数。

我想得到如下结果:

A/0.1
ans =
  88.68

其中的尾随零无关紧要,只要它们只是零,并且在第 14 位左右不包含某个数字。

有趣的是,当四舍五入到 N 数字时也会弹出这个问题:

R = (randi([8659 49847],[1e3 1]))/1e3;
xmin = min(R);
el = 0.1;
step = 1/el;
tmp1=xmin/el;
tmp2=round(tmp1);
tmp3=round(tmp2*el,3);

tmp3 =
   8.699999999999999

【问题讨论】:

  • 只是出于好奇:为什么会这样?为什么不乘以 10?
  • @AnderBiguri 因为在我的情况下,我的网格大小以厘米为单位,这意味着它也可以是例如0.25、0.12 或客户想要的任何值。
  • @AnderBiguri A*10 在这种情况下也不精确......
  • 但问题永远存在。这不是因为您在进行浮点运算时失去了精度,而是因为您无法将所需的数字存储在浮点数中。您始终可以将其存储为带有小数位数信息的 int 或 char,但是一旦转换为浮点数,您将失去该准确性。问题是不可能将88.68 作为浮点数存储在内存中。

标签: matlab precision


【解决方案1】:

使用符号数学,可以得到精确的结果:

x=sym('8.868')/sym('.1')

【讨论】:

  • 这在速度方面是如何工作的?由于我有大约 8 亿个数据点,因此速度是一个重要问题。
  • 符号数学非常慢,对于这样的数据量来说可能是不可能的。
【解决方案2】:

您始终可以使用斜率是 10 的倍数的 fixed point 算术。当您乘以/除以 10 时,您不会有任何不准确性。在 Matlab 中可以使用Fixed Point Toolbox

编辑:根据您的评论 - 看起来您可以将斜率设置为 0.05。

【讨论】:

  • 正如我在 my comment 中指出的那样,斜率并不总是 10 的倍数。
  • @Adriaan,你能找到斜率的公倍数吗?否则,您始终可以使用无限精度数学。
  • 我的数据是毫米精度数据,即三位数,我想在 X cm 的网格中分箱,其中 X 由客户要求的分辨率决定。通常 X 为 0.1、0.25 或 0.5 m,因此这就是数据需要四舍五入的值。
【解决方案3】:

发布此答案只是为了在我的情况下完整。


我使用unique 的第三个输出在某种程度上规避了这个问题:

el = 0.25;
A = (randi([7364 84635],[1e4 1]))/1e3;
B = A/el;
C = round(B);
D = C*el;
[tmp1,tmp2,tmp3] = unique(D);
E = tmp1(tmp3,:);
all(E==D)
ans = 
     1

正确地进行分箱。因此,即使中心点可能不是无限精确的,但它们至少在 10 位以内,这比我原始数据的 3 位精度还要高。

【讨论】:

    【解决方案4】:

    您可以将数字表示为整数的分数。只要不转换为浮点数,就不会丢失精度:

    A = 8.868;
    div = 0.1;
    [N1,D1] = rat(A);
    [N2,D2] = rat(div);
    % divide A by div:
    N = N1 * D2;
    D = N2 * D1;
    

    当然,正如其他答案/cmets 中所述,您的数字一开始可能并不精确。转换为分数也可以引入近似值,但这取决于您处理的数字以及 rattol 参数。

    【讨论】:

      猜你喜欢
      • 2020-08-29
      • 1970-01-01
      • 1970-01-01
      • 2021-07-10
      • 1970-01-01
      • 2020-04-24
      • 2011-11-17
      • 1970-01-01
      • 2019-10-31
      相关资源
      最近更新 更多