欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java正確比較浮點數(shù)的方法

 更新時間:2020年11月09日 09:00:34   作者:平醬  
這篇文章主要介紹了Java正確比較浮點數(shù)的方法,幫助大家更好的利用Java比較浮點數(shù)數(shù)據(jù),感興趣的朋友可以了解下

看下面這段代碼,將 d1 和 d2 兩個浮點數(shù)進行比較,輸出的結(jié)果會是什么?

double d1 = .1 * 3;
double d2 = .3;
System.out.println(d1 == d2);

按照正常邏輯來看,d1經(jīng)過計算之后的結(jié)果應(yīng)該是0.3,最后打印的結(jié)果應(yīng)該是 true,對吧?但是運行一下就會發(fā)現(xiàn)結(jié)果并不是 true 而是 false 。

輸出一下 d1,發(fā)現(xiàn)得到的答案不是想象中的 0.3 而是 0.30000000000000004,所以和 d2 進行比較結(jié)果自然是 false

如何正確地比較浮點數(shù)(單精度的 float 和雙精度的 double),不單單是 Java 特定的問題,在計算機的內(nèi)存中,存儲浮點數(shù)時使用的是 IEEE 754 標(biāo)準(zhǔn),就會有精度的問題。

存儲和轉(zhuǎn)換的過程中浮點數(shù)容易引起一些較小的舍入誤差,正是這個原因,導(dǎo)致在比較浮點數(shù)的時候,不能使用“==”操作符——要求嚴(yán)格意義上的完全相等。

那么如何正確的比較浮點數(shù)呢?這里有兩種方案。

  • 第一種方案是允許兩個值之間存在一點誤差(指定一個閾值),使用 Math.abs() 方法來計算兩個浮點數(shù)之間差異的絕對值,如果這個差異在閾值范圍之內(nèi),我們就認(rèn)為兩個浮點數(shù)是相等的。
final double THRESHOLD = .0001;

double d1 = .1 * 3;
double d2 = .3;

if(Math.abs(d1-d2) < THRESHOLD) {
	System.out.println("d1 和 d2 相等");
} else {
	System.out.println("d1 和 d2 不相等");
}

Math.abs() 方法用來返回 double 的絕對值,如果 double 小于 0,則返回 double 的正值,否則返回 double。也就是說,abs() 后的結(jié)果絕對大于 0,如果結(jié)果小于閾值(THRESHOLD),我們就認(rèn)為 d1 和 d2 相等。

  • 第二種方案是使用 BigDecimal 類,可以指定要舍入的模式和精度,這樣就可以解決舍入的誤差。

以使用 BigDecimal 類的 compareTo() 方法對兩個數(shù)進行比較,該方法將會忽略小數(shù)點后的位數(shù),怎么理解這句話呢?比如說 2.0 和 2.00 的位數(shù)不同,但它倆的值是相等的。

a.compareTo(b) 如果 a 和 b 相等,則返回 0,否則返回 -1。

tips: 不要使用 equals() 方法對兩個 BigDecimal 對象進行比較,這是因為 equals() 方法會考慮位數(shù),如果位數(shù)不同,則會返回 false,盡管數(shù)學(xué)值是相等的。

BigDecimal a = new BigDecimal("2.00");
BigDecimal b = new BigDecimal("2.0");

System.out.println(a.equals(b));
System.out.println(a.compareTo(b) == 0);

上面的代碼中 a.equals(b) 的結(jié)果就為 false,因為 2.00 和 2.0 小數(shù)點后的位數(shù)不同,但 a.compareTo(b) == 0 的結(jié)果就為 true,因為 2.00 和 2.0 在數(shù)學(xué)層面的值的確是相等的。

compareTo() 方法比較的過程非常嚴(yán)謹(jǐn),源碼如下:

private int compareMagnitude(BigDecimal val) {
  // Match scales, avoid unnecessary inflation
  long ys = val.intCompact;
  long xs = this.intCompact;
  if (xs == 0)
    return (ys == 0) ? 0 : -1;
  if (ys == 0)
    return 1;

  long sdiff = (long)this.scale - val.scale;
  if (sdiff != 0) {
    // Avoid matching scales if the (adjusted) exponents differ
    long xae = (long)this.precision() - this.scale;  // [-1]
    long yae = (long)val.precision() - val.scale;   // [-1]
    if (xae < yae)
      return -1;
    if (xae > yae)
      return 1;
    if (sdiff < 0) {
      // The cases sdiff <= Integer.MIN_VALUE intentionally fall through.
      if ( sdiff > Integer.MIN_VALUE &&
          (xs == INFLATED ||
              (xs = longMultiplyPowerTen(xs, (int)-sdiff)) == INFLATED) &&
          ys == INFLATED) {
        BigInteger rb = bigMultiplyPowerTen((int)-sdiff);
        return rb.compareMagnitude(val.intVal);
      }
    } else { // sdiff > 0
      // The cases sdiff > Integer.MAX_VALUE intentionally fall through.
      if ( sdiff <= Integer.MAX_VALUE &&
          (ys == INFLATED ||
              (ys = longMultiplyPowerTen(ys, (int)sdiff)) == INFLATED) &&
          xs == INFLATED) {
        BigInteger rb = val.bigMultiplyPowerTen((int)sdiff);
        return this.intVal.compareMagnitude(rb);
      }
    }
  }
  if (xs != INFLATED)
    return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1;
  else if (ys != INFLATED)
    return 1;
  else
    return this.intVal.compareMagnitude(val.intVal);
}

接下來,用 BigDecimal 來解決開頭的問題。

BigDecimal d1 = new BigDecimal("0.1");
BigDecimal three = new BigDecimal("3");
BigDecimal d2 = new BigDecimal("0.3");

d1 = d1.multiply(three);

System.out.println("d1 = " + d1);
System.out.println("d2 = " + d2);
System.out.println(d1.compareTo(d2));

程序輸出的結(jié)果如下:

d1 = 0.3
d2 = 0.3
0

d1 和 d2 都為 0.3,所以 compareTo() 的結(jié)果就為 0,表示兩個值是相等的。

總結(jié)一下,在遇到浮點數(shù)的時候,千萬不要使用 == 操作符來進行比較,因為有精度問題。要么使用閾值來忽略舍入的問題,要么使用 BigDecimal 來替代 double 或者 float。

以上就是Java正確比較浮點數(shù)的方法的詳細(xì)內(nèi)容,更多關(guān)于Java 正確比較浮點數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java程序命令行參數(shù)用法總結(jié)

    Java程序命令行參數(shù)用法總結(jié)

    這篇文章主要介紹了Java程序命令行參數(shù)用法總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java 通過cmd 調(diào)用命令啟動tomcat的操作

    java 通過cmd 調(diào)用命令啟動tomcat的操作

    這篇文章主要介紹了java 通過cmd 調(diào)用命令啟動tomcat的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • SpringBoot結(jié)合Redis實現(xiàn)緩存

    SpringBoot結(jié)合Redis實現(xiàn)緩存

    本文主要介紹了SpringBoot結(jié)合Redis實現(xiàn)緩存,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 在Java中使用日志框架log4j的方法

    在Java中使用日志框架log4j的方法

    Log4j有三個主要的組件/對象:Loggers(記錄器),Appenders (輸出源)和Layouts(布局)。這里可簡單理解為日志類別,日志要輸出的地方和日志以何種形式輸出,今天通過本文給大家分享Java日志框架log4j的相關(guān)知識,感興趣的朋友一起看看吧
    2021-08-08
  • Redis中String字符串和sdshdr結(jié)構(gòu)體超詳細(xì)講解

    Redis中String字符串和sdshdr結(jié)構(gòu)體超詳細(xì)講解

    這篇文章主要介紹了Redis中String字符串和sdshdr結(jié)構(gòu)體,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-04-04
  • java ThreadGroup的作用及方法詳解

    java ThreadGroup的作用及方法詳解

    這篇文章主要介紹了java ThreadGroup的作用及方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • SpringBoot 項目如何在tomcat容器中運行的實現(xiàn)方法

    SpringBoot 項目如何在tomcat容器中運行的實現(xiàn)方法

    這篇文章主要介紹了SpringBoot 項目如何在tomcat容器中運行的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Spring項目里將SQL語句寫在.sql文件中的方法

    Spring項目里將SQL語句寫在.sql文件中的方法

    這篇文章主要介紹了Spring項目里如何將SQL語句寫在.sql文件中的方法,文中給出了詳細(xì)的介紹和示例代碼,相信對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,有需要的朋友們下面來一起看看吧。
    2017-01-01
  • Java復(fù)雜鏈表的復(fù)制詳解

    Java復(fù)雜鏈表的復(fù)制詳解

    復(fù)雜鏈表指的是一個鏈表有若干個結(jié)點,每個結(jié)點有一個數(shù)據(jù)域用于存放數(shù)據(jù),還有兩個指針域,其中一個指向下一個節(jié)點,還有一個隨機指向當(dāng)前復(fù)雜鏈表中的任意一個節(jié)點或者是一個空結(jié)點,我們來探究一下在Java中復(fù)雜鏈表的復(fù)制
    2022-01-01
  • Java實現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件

    Java實現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件

    這篇文章主要介紹了Java如何實現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)java有一定的幫助,感興趣的同學(xué)可以了解一下
    2021-12-12

最新評論