在Java中,长值如何在不损失精度的情况下适合浮点数据类型

在Java中,长值如何在不损失精度的情况下适合浮点数据类型,java,floating-point,precision,long-integer,Java,Floating Point,Precision,Long Integer,在Java中,长值如何适应浮点数据类型而不损失精度。因为如果丢失了精度,那么应该生成以下代码段 long lMax = Long.MAX_VALUE; float f = lMax; System.out.println(lMax == f); Output true 问题是,对于long和float的比较,long值被转换为float,与赋值中发生的精度损失相同 如果要“检测”精度损失,请尝试使用BigDecimals,如下所示: System.out.println(new BigDe

在Java中,长值如何适应浮点数据类型而不损失精度。因为如果丢失了精度,那么应该生成以下代码段

long lMax = Long.MAX_VALUE;
float f = lMax;
System.out.println(lMax == f);

Output 
true

问题是,对于
long
float
的比较,
long
值被转换为
float
,与赋值中发生的精度损失相同

如果要“检测”精度损失,请尝试使用
BigDecimal
s,如下所示:

System.out.println(new BigDecimal(lMax).compareTo(new Bigdecimal(f)));
我知道构造函数
BigDecimal(double)
会将
float
转换为
double
,但不会丢失精度

编辑 对大多数人来说,
long
似乎比
float
更“精确”。然而,
float
的范围是
+/-10^38
,这比
long
的范围大得多

测验 产出:

true
-1
true
true
9223372036854775807, 9223372036854775807
true
-1
false
true
9223372036854775807, 9223372036854775806

lMax的值=9223372036854775807;//在JVM中可能会有所不同

f值=9.223372E18

现在,当您比较
lMax==f
时,首先将f转换为long,然后进行比较。转换为long后,f值与lMax相同

同样的情况也适用于以下代码

long lMax = Long.MAX_VALUE; // value is 9223372036854775807
float f =lMax;
float f2 = 9223372036854775807.5f;
System.out.println(lMax == f);
System.out.println(lMax == f2);
输出

true
true

这里,与long相比,f2失去了十进制值。f2的长值与lMax相同。

lMax是一个长数。将其指定为浮点值时,将失去精度

浮点数f=lMax

将long与float进行比较时,在内部,long转换为float,或者float转换为long。你的代码

lMax==f

将类似于

((Float)f).longValue()==lMax

这是9.223372E18==9.223372E18 true

((长)lMax).floatValue()==f

这是9223372036854775807==9223372036854775807 true

无论哪种方式,答案都是正确的。

Java语言规范中的规则是理解问题中代码片段行为的关键。特别是“否则,如果其中一个操作数的类型为float,则另一个操作数将转换为float。”


lMax==f
比较中,lMax被转换为float,与
float f=lMax
赋值完全相同。如果您使用相同的输入值,请对其执行两次相同的转换,并比较结果,无论转换是否更改了值,结果都是相等的。

如果您想很好地演示精度损失,请在获取系统时间(毫秒)并从长时间转换为浮点时间时尝试以下小脚本:

class Scratch {
    public static void main(String[] args) throws InterruptedException {

        float currentF;
        long currentL;
        float lastNewF = 0;
        long lastL = System.currentTimeMillis();
        long diff;

        while (true) {
            currentL = System.currentTimeMillis();
            currentF = (float) currentL;
            if (currentF != lastNewF) {
                // we finally got a new "different" float value
                lastNewF = currentF;
                diff = currentL - lastL;
                lastL = currentL;
                System.out.println(diff + " milliseconds since we got a new time as float");
            }
            Thread.sleep(250);
        }
    }
}
从输出中可以看出,有时会损失高达2分钟的精度:

0 milliseconds since we got a new time as float
46964 milliseconds since we got a new time as float
131054 milliseconds since we got a new time as float
131093 milliseconds since we got a new time as float
131077 milliseconds since we got a new time as float

如果
f
丢失精度,将其转换回
long
将导致不同的
long
值,并且可以看到丢失的精度。。。(一般来说,不是关于
Long.MAX_VALUE
…)不,它将给出相同的结果。检查一下,我很关心这个问题。总的来说,您所说的是正确的。
Long.MAX_值-1
给出了
false
。。。。(
System.out.printf(“%d,%d%n”,((Float)f.longValue(),lMax);
输出:
9223372036854775807,9223372036854775806
)是的,没错。但在这里,他处理的是
Long.MAX\u值。这就是我为什么这么说的原因。这是另一种方式。浮点值被转换为long。浮动f2=9223372036854775807.5f;System.out.println(lMax==f2);甚至这也会变成现实。见下面我的答案。
0 milliseconds since we got a new time as float
46964 milliseconds since we got a new time as float
131054 milliseconds since we got a new time as float
131093 milliseconds since we got a new time as float
131077 milliseconds since we got a new time as float