简体   繁体   English

如何在Double中检查浮点精度

[英]How to check for floating point precision in Double

Take this simple function for example. 以这个简单的功能为例。

   int checkIfTriangleIsValid(double a, double b, double c) {
      //fix the precision problem
      int c1, c2, c3;
      c1 = a+b>c ? 0 : 1;
      c2 = b+c>a ? 0 : 1;
      c3 = c+a>b ? 0 : 1;
      if(c1 == 0 && c2 == 0 && c3 == 0)
        return 0;
      else {
        printf("%d, %d, %d\n",c1, c2, c3);
        return 1;
      }
   } 

I place for a = 1.923 , b = 59.240 , c = 61.163 我放置a = 1.923b = 59.240c = 61.163

Now for some reason when I check for the condition in c1 it should give me 1, but instead, it gives me 0. I tried to do a printf with %.30f and found that the values later changes. 现在由于某种原因,当我检查c1中的条件时,它应该给我1,但是,它却给我0。我尝试使用%.30f进行printf ,发现以后值会更改。

How can I fix this problem? 我该如何解决这个问题?

EDIT: I checked the other questions that are similar to mine but they don't even have a double. 编辑:我检查了其他类似我的问题,但他们甚至没有双。

Likely your C implementation uses the IEEE-754 basic 64-bit binary floating-point format for double . 您的C实现可能使用double的IEEE-754基本64位二进制浮点格式。 When 1.923 , 59.240 , and 61.163 are properly converted to the nearest values representable in double , the results are exactly: 1.92359.240 ,和61.163被正确地转换为可表示在最近的值double ,结果是完全:

  • 1.9230000000000000426325641456060111522674560546875, 1.9230000000000000426325641456060111522674560546875,
  • 59.24000000000000198951966012828052043914794921875, and 59.24000000000000198951966012828052043914794921875和
  • 61.1629999999999967030817060731351375579833984375. 61.1629999999999967030817060731351375579833984375。

As you can see, the first two of these sum to more than the third. 如您所见,其中的前两个总和大于第三个。 This means that, by the time you assign these values to double objects, they have already been altered in a way that changes their relationship. 这意味着,当您将这些值分配给double对象时,它们已经以改变其关系的方式进行了更改。 No subsequent calculations can repair this, because the original information is gone. 由于原始信息已消失,因此后续计算无法修复。

Since no solution after conversion to double can work, you need a solution that operates before or instead of conversion to double . 由于转换为double 没有解决方案可以工作,因此您需要一个在转换为double之前或代替其运行的解决方案。 If you want to compute exactly, or more precisely, with the values 1.923, 59.240, and 61.163, you may need to write your own decimal arithmetic code or find some other code that supports decimal arithmetic. 如果要使用值1.923、59.240和61.163精确地或更精确地计算,则可能需要编写自己的十进制算术代码或查找其他支持十进制算术的代码。 If you only want to work with numbers with three decimal places, then a possible solution is to write some code that reads input such as “59.240” and returns it in an integer object scaled by 1000, so that 59240 is returned. 如果只想使用小数点后三位的数字,则可能的解决方案是编写一些读取输入的代码,例如“ 59.240”,然后将其返回到以1000缩放的整数对象中,从而返回59240。 The resulting values could then easily be tested for the triangle inequality. 然后可以容易地测试所得值的三角形不等式。

when I check for the condition in c1 it should give me 1, but instead it gives me 0 当我检查c1中的条件时,应该给我1,但是给我0
How can I fix this problem? 我该如何解决这个问题?

Change your expectations. 改变您的期望。

A typical double can represent exactly about 2 64 different values. 一个典型的double可以精确表示大约2 64个不同的值。 1.923, 59.240, 61.163 are typically not in that set as double is usually encoded in a binary way. 1.923、59.240、61.163通常不在该集合中,因为double通常以二进制方式进行编码。 eg binary64 . 例如binary64

When a,b,c are assigned 1.923, 59.240, 61.163, they get values more like the below which are the closet double . 当为a,b,c分配1.923、59.240、61.163时,它们获得的值更像下面的值,即壁橱double

a      1.923000000000000042632564145606...
b     59.240000000000001989519660128281...
c     61.162999999999996703081706073135...

In my case, the a , and b both received a slightly higher value than the decimal code form, while c received a slightly lower one. 在我的情况下, ab都收到比十进制代码形式稍高的值,而c收到略低于十进制代码形式的值。

When adding a+b , the sum was rounded up, further away from c . a+b ,总和四舍五入,远离c

printf("a+b %35.30f\n", a+b);
a+b   61.163000000000003808509063674137

a + b > c was true, as well as other compares and OP's a + b > c以及其他比较和OP均为真
checkIfTriangleIsValid(1.923, 59.240, 61.163) should return valid (0) as it is really more like checkIfTriangleIsValid(1.9230000000000000426..., 59.24000000000000198..., 61.16299999999999670...) checkIfTriangleIsValid(1.923, 59.240, 61.163) 应该返回有效 (0),因为它实际上更像是checkIfTriangleIsValid(1.9230000000000000426..., 59.24000000000000198..., 61.16299999999999670...)


Adding a+b is further complicated in that the addition may occur using double or long double math. a+b更加复杂,因为加法可能使用doublelong double数学进行。 Research FLT_EVAL_METHOD for details. 研究FLT_EVAL_METHOD了解详细信息。 Rounding mode also can affect the final sum. 取整模式也会影响最终的总和。

#include <float.h>
printf("FLT_EVAL_METHOD %d\n", FLT_EVAL_METHOD);

As to an alternative triangle check, subtract the largest 2 values and then compare against the smallest. 对于替代的三角检查,请减去最大的2个值,然后与最小的值进行比较。

a > (cb) can preserve significantly more precision than (a+b) > c . a > (cb)可以比(a+b) > c保留更高的精度。

// Assume a,b,c >= 0
int checkIfTriangleIsValid_2(double a, double b, double c) {
  // Sort so `c` is largest, then b, a.
  if (c < b) {
    double t = b; b = c; c = t;
  }
  if (c < a) {
    double t = a; a = c; c = t;
  }
  if (a > b) {
    double t = b; b = a; a = t;
  }
  // So far, no loss of precision is expected due to compares/swaps.
  // Only now need to check a + b >= c for valid triangle

  // To preserve precision, subtract from `c` the value closest to it (`b`).
  return a > (c-b);
}

I will review more later as time permits. 如果时间允许,我将在以后进行更多审查。 This approach significant helps for a precise answer - yet need to assess more edge cases. 这种方法对准确的答案很有帮助-但需要评估更多的极端情况。 It reports a valid triangle checkIfTriangleIsValid_2(1.923, 59.240, 61.163)) . 它报告一个有效的三角形checkIfTriangleIsValid_2(1.923, 59.240, 61.163))

FLT_EVAL_METHOD , rounding mode and double encoding can result in different answers on other platforms. FLT_EVAL_METHOD ,舍入模式和double编码可能在其他平台上导致不同的答案。


Notes: 笔记:
It appears a checkIfTriangleIsValid() returning 0 means valid triangle . 出现一个checkIfTriangleIsValid()返回0表示有效三角形
It also appears when the triangle has 0 area, the expected result is 1 or invalid . 当三角形的面积为0,预期结果为1或invalid时,它也会出现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM