如何正确比较long和float原语?

时间:2015-07-31 11:20:35

标签: java primitive-types

出于某种原因,我需要比较两个基元:long和float。

我可以使用以下代码吗?

long a = 111L;
float b = 111.1f

if (a > b) {
  ...
}

我知道,浮点数和浮点数可以与使用epsilon值等进行比较。

但我怎样才能更准确地比较我的情况?

感谢所有人。

4 个答案:

答案 0 :(得分:3)

你可以将它们都包裹在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.   
  3. 应用扩展基元转换(第5.1.2节)来转换   或者由以下规则指定的两个操作数:

         
        
    • 如果任一操作数的类型为double,则另一个操作数将转换为   double

    •   
    • 否则,如果任一操作数的类型为float,则转换另一个操作数   到float

    •   
    • 否则,如果任一操作数的类型为long,则转换另一个操作数   到long

    •   
    • 否则,两个操作数都将转换为int类型。

    •   
  4.   

有了这个,我们可以得出结论,对于比较a > blong操作数将被隐式提升为float。但是,这可能会导致精度损失,如JLS 5.1.2 Widening primitive conversion中所述:

  

intlong值扩展为float或更长的转换   值加倍,可能导致精度损失 - 即结果   可能会丢失该值的一些最低有效位。在这   case,生成的浮点值将是正确舍入的   使用IEEE 754舍入到最接近模式的整数值的版本   (§4.2.4)。

答案 1 :(得分:1)

如果您想使用epsilon,您可以

>>> class A(object):
...     def __str__(self):
...         return 'a','b'
...
>>> a = A()
>>> print a.__str__()
('a', 'b')
>>> print str(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __str__ returned non-string (type tuple)

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

如果您可以假设非负数,则可以删除Math.sign(b)。

但是,在这种情况下使用BigDecimal可能会更清楚,请参阅@ kocko的回答。

BTW:提高准确性的最简单的变化是使用// 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) 代替doublefloat的准确度几乎提高了五十亿倍,除非你拥有数十亿,否则你使用的提取记忆无关紧要。

答案 2 :(得分:0)

Java支持直接比较long和float。但是,有一些警告:

如果比较long和float,则long被转换为float,因为float被认为是比long更宽的类型。但是,此转换可能会失去精度:long值将转换为最接近的float值;因此,对于较长的a和一个b a > b,如果a实际上是b b大于b,则BigDecimal可能为假最接近BigDecimal的值。

每个long和float值都可以用long a = ...; float b = ...; if (BigDecimal.valueOf(a).compareTo(BigDecimal.valueOf(b)) > 0) { ... } 表示,所以你也可以使用Logger.log(JSON.stringify(new_arr)); 类来比较long和float:

CREATE TABLE #TABLE
(
    [WEEK] INT,
    [WEEK_DATA] VARCHAR(100)
)

INSERT INTO #TABLE
SELECT 1, 'DATA FOR WEEK 1' UNION
SELECT 3, 'DATA FOR WEEK 3' UNION
SELECT 10, 'DATA FOR WEEK 10'

SELECT * FROM #TABLE

---

DECLARE @WEEK INT
SET @WEEK = 1

DECLARE @DUMMY TABLE
(
    [WEEK] INT 
)

WHILE @WEEK <= 52
BEGIN
    INSERT INTO @DUMMY
    SELECT @WEEK
    SET @WEEK = @WEEK + 1
END

SELECT
    T1.[WEEK],
    WEEK_DATA = CASE WHEN T2.WEEK_DATA IS NULL THEN 'NO DATA' ELSE T2.WEEK_DATA END
FROM
    @DUMMY AS T1
LEFT JOIN
    #TABLE AS T2 ON T1.[WEEK] = T2.[WEEK]

答案 3 :(得分:0)

轻松使用此代码:

Double.compare(longVar * 1., floatVar)