搜尋

首頁  >  問答  >  主體

java - 浮点数如何比较是否相等或者如何判断某个浮点数是否为0?

大家应该都知道浮点数存在精度问题,所以问题就来了,我如何才能判断两个数是否近似相等,或者某个浮点数是否为0。
其实这是一个问题,对于前者,我们需要二者作差,然后与0进行比较。这样前者与后者就是同一个问题了,即如何判断某个浮点数是否为0。我所知道的比较简单但是不是很好的方法就是使用1e-7或者更小的数,如下所示(以单精度为例):

#include <iostream>
#include <cfloat>

using namespace std;

int main()
{
    float num;

    cout << "输入一个数:";
    cin >> num;

    if (num < 1e-7 && num > -1e-7)
        cout << num << "近似为0" << endl;
    else
        cout << num << "不近似为0" << endl;

    return 0;
}

上述方式以C++代码为例。由于不同编程语言有不同的处理方式,大家可以不限制使用任何编程语言。当然,如果您有更通用的方式当然再好不过了。

天蓬老师天蓬老师2781 天前1936

全部回覆(3)我來回復

  • PHP中文网

    PHP中文网2017-04-18 10:20:47

    多小才是“足夠小”,應該是由處理的具體問題決定的。例如用double表示金额的话,1e-4就可以认为是零了。而如果进行科学计算,恐怕1e-7還嫌太大。

    <cfloat>中有定义DBL_EPSILON为与1.0最接近的差。參見這裡。

    回覆
    0
  • PHPz

    PHPz2017-04-18 10:20:47

    浮點數的比較還是要根據實際儲存規則來,因為浮點數是以二進制來儲存的,而用二進位表示十進制是不能精確表示的,即使浮點數的十進制有效數字比較少,那也不一定能用二進制精確表示。為什麼呢?
    首先浮點數小數位的二進位是這樣對應的:
    小數後1位:0.5 (2^-1)
    小數後2位:0.25 (2^-2)
    ...
    小數位n位:2 ^-n
    也就是說,任何一個浮點數的小數部分都是由2^-1 ... 2^-n組合而成的,這樣就能理解為什麼有效位數少的浮點數也不能精確表示了,例如0.3,就無法用上面的位數組合而精確表示出來,不信cout試試:

    #include <iostream>
    #include <iomanip>
    
    int main()
    {
        float a = 0.3f;
        std::cout << std::setprecision(32) << a << std::endl;
        return 0;
    }

    輸出:0.30000001192092896
    而如果把0.3換成0.5,那就可以了,因為0.5可以用2^-1精確表示啊!同理,0.625也可以。
    那我們平常為什麼cout << 0.3;可以直接輸出0.3呢?那是因為cout預設做了舍入處理

    回到樓主的問題:如果是直接判斷0.3 == 0.3,那沒問題,因為同樣的數字做了同樣的表示,所以可以直接用'=='。如果是可以精確表示的數,例如0,則更是如此了。
    但是如果判斷0.1+0.2和0.3是否相等,那就不行了,因為他們都有精度損失,而損失的數值又不一樣,所以不能直接比較需要用abs((0.1+0.2) - 0.3)<EPSILON這樣的方法。

    回覆
    0
  • 天蓬老师

    天蓬老师2017-04-18 10:20:47

    計算機表示浮點數(float或double類型)都有一個精度限制,對於超出了精度限制的浮點數,計算機會把它們的精度之外的小數部分截斷。因此,本來不相等的兩個浮點數在計算機中可能就變成相等的了。例如:

    float a=10.222222225,b=10.222222229
    数学上a和b是不相等的,但在32位计算机中它们是相等的。
    
    如果两个同符号浮点数之差的绝对值小于或等于某一个可接受的误差(即精度),就认为它们是相等的。
    不要直接用“==”或者“!=”对两个浮点数进行比较,但是可以直接用“<”和“>”比较谁大谁小。
    

    回覆
    0
  • 取消回覆