簡體   English   中英

如何在Double中檢查浮點精度

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

以這個簡單的功能為例。

   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;
      }
   } 

我放置a = 1.923b = 59.240c = 61.163

現在由於某種原因,當我檢查c1中的條件時,它應該給我1,但是,它卻給我0。我嘗試使用%.30f進行printf ,發現以后值會更改。

我該如何解決這個問題?

編輯:我檢查了其他類似我的問題,但他們甚至沒有雙。

您的C實現可能使用double的IEEE-754基本64位二進制浮點格式。 1.92359.240 ,和61.163被正確地轉換為可表示在最近的值double ,結果是完全:

  • 1.9230000000000000426325641456060111522674560546875,
  • 59.24000000000000198951966012828052043914794921875和
  • 61.1629999999999967030817060731351375579833984375。

如您所見,其中的前兩個總和大於第三個。 這意味着,當您將這些值分配給double對象時,它們已經以改變其關系的方式進行了更改。 由於原始信息已消失,因此后續計算無法修復。

由於轉換為double 沒有解決方案可以工作,因此您需要一個在轉換為double之前或代替其運行的解決方案。 如果要使用值1.923、59.240和61.163精確地或更精確地計算,則可能需要編寫自己的十進制算術代碼或查找其他支持十進制算術的代碼。 如果只想使用小數點后三位的數字,則可能的解決方案是編寫一些讀取輸入的代碼,例如“ 59.240”,然后將其返回到以1000縮放的整數對象中,從而返回59240。 然后可以容易地測試所得值的三角形不等式。

當我檢查c1中的條件時,應該給我1,但是給我0
我該如何解決這個問題?

改變您的期望。

一個典型的double可以精確表示大約2 64個不同的值。 1.923、59.240、61.163通常不在該集合中,因為double通常以二進制方式進行編碼。 例如binary64

當為a,b,c分配1.923、59.240、61.163時,它們獲得的值更像下面的值,即壁櫥double

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

在我的情況下, ab都收到比十進制代碼形式稍高的值,而c收到略低於十進制代碼形式的值。

a+b ,總和四舍五入,遠離c

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

a + b > c以及其他比較和OP均為真
checkIfTriangleIsValid(1.923, 59.240, 61.163) 應該返回有效 (0),因為它實際上更像是checkIfTriangleIsValid(1.9230000000000000426..., 59.24000000000000198..., 61.16299999999999670...)


a+b更加復雜,因為加法可能使用doublelong double數學進行。 研究FLT_EVAL_METHOD了解詳細信息。 取整模式也會影響最終的總和。

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

對於替代的三角檢查,請減去最大的2個值,然后與最小的值進行比較。

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);
}

如果時間允許,我將在以后進行更多審查。 這種方法對准確的答案很有幫助-但需要評估更多的極端情況。 它報告一個有效的三角形checkIfTriangleIsValid_2(1.923, 59.240, 61.163))

FLT_EVAL_METHOD ,舍入模式和double編碼可能在其他平台上導致不同的答案。


筆記:
出現一個checkIfTriangleIsValid()返回0表示有效三角形
當三角形的面積為0,預期結果為1或invalid時,它也會出現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM