浮点算术

时间:2017-04-10 16:00:46

标签: c++ c floating-point precision floating-point-conversion

今天在我的C ++编程课程中,我的proff告诉我,不应该直接比较两个浮点值。

所以我尝试了这段代码并找出了他陈述的原因。

{
"intents": [
  {
    "intent": "ActorIntent"
  },
  {
    "slots": [
      {
        "name": "skill",
        "type": "SKILL"
      }
    ],
    "intent": "SkillIntent"
  }
}

我发现结果为94.89999999(一些相对误差)

我知道浮动数字不会以将其呈现给代码的方式存储。以二进制形式压缩那些零和零会涉及一些相对舍入误差。

我正在寻找两个问题的解决方案。 1.比较两个浮动值的有效方法。 2.如何将浮动值添加到另一个浮动值。例。添加0.1111到94.4345以获得准确值94.5456

提前致谢。

3 个答案:

答案 0 :(得分:1)

  
      
  1. 比较两个浮动值的有效方法。
  2.   

简单的double a,b; if (a == b)是比较两个浮动值的有效方法。然而,正如OP所注意到的,这可能无法满足整体编码目标。更好的方法取决于比较的上下文,这不是OP提供的。见下文。

  
      
  1. 如何将浮动值添加到另一个浮动值。例。添加0.1111到94.4345以获得准确值94.5456
  2.   

浮动值作为源代码具有有效的无限范围和精度,例如1.23456789012345678901234567890e1234567。将此文本转换为double通常限制为2个 64 不同值中的一个。选择最近的,但可能不完全匹配。

0.1111, 94.4345, 94.5456都不能代表完全作为典型的double

OP有选择:

1。)使用double, float以外的其他类型。各种库提供十进制浮点类型。

2)将代码限制为支持double到基础10表单的稀有平台,FLT_RADIX == 10

3)编写自己的代码,将"0.1111"之类的用户输入处理到结构/字符串中,然后执行所需的操作。

4)将用户输入视为字符串并转换为某种整数类型,再次使用支持的例程来读取/计算/写入。

5)接受浮点运算在数学上不精确并处理舍入误差。

double a = 0.1111;
printf("a:   %.*e\n", DBL_DECIMAL_DIG -1 , a);
double b = 94.4345;
printf("b:   %.*e\n", DBL_DECIMAL_DIG -1 , b);
double sum = a + b;
printf("sum: %.*e\n", DBL_DECIMAL_DIG -1 , sum);
printf("%.4f\n", sum);

输出

a:   1.1110000000000000e-01
b:   9.4434500000000000e+01
sum: 9.4545599999999993e+01
94.5456  // Desired textual output based on a rounded `sum` to the nearest 0.0001
  

更多关于#1

如果没有寻找完全比较但是某种“两个值足够接近吗?”,则需要“足够接近”的定义 - 其中有很多。

以下“足够接近”通过检查两个数字的ULP来比较距离。当值处于相同的2的幂时,它是线性差异,而在其他方面变为对数。当然,改变标志是一个问题。

float示例:
考虑从最负面到最正面排序的所有有限float。以下有点可移植的代码为每个float返回一个整数,其中相同的顺序

uint32_t sequence_f(float x) {
  union {
    float f;
    uint32_t u32;
  } u;
  assert(sizeof(float) == sizeof(uint32_t));
  u.f = x;
  if (u.u32 & 0x80000000) {
    u.u32 ^= 0x80000000;
    return 0x80000000 - u.u32;
  }
  return u.u3
}

现在,要确定两个float是否“足够接近”,简单比较两个整数。

static bool close_enough(float x, float y, uint32_t ULP_delta) {
  uint32_t ullx = sequence_f(x);
  uint32_t ully = sequence_f(y);
  if (ullx > ully) return (ullx - ully) <= ULP_delta;
  return (ully - ullx) <= ULP_delta;
}

答案 1 :(得分:0)

我通常采用的方法是使用自定义相等比较功能。基本的想法是,你有一定的容忍度,比如0.0001或者其他什么。然后你减去你的两个数字并取其绝对值,如果它小于你的容差,你就把它视为平等。当然,还有其他策略可能更适合某些情况。

答案 2 :(得分:0)

  1. 为自己定义容差级别e(例如e=.0001)并检查abs(a-b) <= e

  2. 你不会得到一个&#34;确切的&#34;浮点值。永远。如果您事先知道您使用的是四位小数,并且您想要&#34;确切&#34;,那么您需要在内部将数字视为整数,并仅将它们显示为小数。 944345 + 1111 = 945456