簡體   English   中英

如何正確比較 long 和 float 原語?

[英]How to compare correctly long and float primitives?

出於某種原因,我需要比較兩個原語:long 和 float。

我可以為此使用以下代碼嗎?

long a = 111L;
float b = 111.1f

if (a > b) {
  ...
}

我知道,可以使用 epsilon 值等將浮點數和浮點數與某些精度進行比較。

但是我怎樣才能更正確地對我的案例進行比較?

謝謝大家。

您可以將它們都包裝在BigDecimal ,然后將它們進行比較:

long a = 111L;
float b = 111.1f;
BigDecimal first = new BigDecimal(a);
BigDecimal second = new BigDecimal(b, MathContext.DECIMAL32);
if (first.compareTo(second) > 0) { ... }

為了理解為什么我們有興趣在同一類型下擁有兩個操作數,讓我們深入研究JLS 5.6.2 Binary Numeric Promotion

當運算符將二進制數字提升應用於一對操作數時,每個操作數必須表示一個可轉換為數字類型的值,以下規則依次適用:

  1. 如果任何操作數是引用類型,則需要進行拆箱轉換(第 5.1.8 節)。

  2. 擴展原語轉換(第 5.1.2 節)用於轉換一個或兩個操作數,如以下規則所指定:

    • 如果任一操作數的類型為double ,則另一個將轉換為double

    • 否則,如果任一操作數的類型為float ,則另一個將轉換為float

    • 否則,如果任一操作數的類型為long ,則另一個將轉換為long

    • 否則,兩個操作數都被轉換為int類型。

有了這個,我們可以得出結論,對於比較a > blong操作數將被隱式提升為float 但是,這可能會導致精度損失,如JLS 5.1.2 Widening 原語轉換中所述

intlong值到float或 long 值到 double 的擴展轉換可能會導致精度損失 - 也就是說,結果可能會丟失值的一些最低有效位。 在這種情況下,生成的浮點值將是整數值的正確舍入版本,使用 IEEE 754 舍入到最近模式(第 4.2.4 節)。

如果你想使用 epsilon 你可以這樣做

// allow for the smallest rounding error
if (a > b + Math.sign(b) * Float.ulp(b))

或者

// assume six digits of precision
static final double ERR = 1e-6;

// allow for the smallest rounding error
if (a > b + Math.sign(b) * b * ERR)

如果您可以假設非負數,則可以刪除 Math.sign(b)。

但是,在這種情況下使用 BigDecimal 可能更清楚,請參閱@kocko 的回答。

順便說一句:可以提高准確性的最簡單的更改是使用double而不是float double實際上准確度高了 50 億倍,除非您擁有數十億個,否則您使用的提取內存將無關緊要。

Java 支持直接比較 long 和 float。 但是,有一些注意事項:

如果比較 long 和 float,則 long 將轉換為 float,因為 float 被認為是比 long 更寬的類型。 但是,這種轉換可能會失去精度:long 值將被轉換為最接近的浮點值; 所以長期a和浮子ba > b雖然可能是假的a大於b ,如果b實際上是最接近浮點值b

每個 long 和 float 值都可以由BigDecimal表示,因此您還可以使用BigDecimal類來比較 long 和 a float:

long a = ...;
float b = ...;
if (BigDecimal.valueOf(a).compareTo(BigDecimal.valueOf(b)) > 0) {
    ...
}

輕松使用此代碼:

Double.compare(longVar * 1., floatVar)

暫無
暫無

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

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