为什么float在Python/PHP/Javascript和Java/C#之间表现不同

dav*_*ode -2 c# python java floating-point precision

10年后,我(重新)学习Java,我正在编写简单的代码,以便检查语法并验证简单的行为.我正在使用数字类型,我不明白为什么浮点数在Java(以及后面验证的C#)中的行为与Python(或其他脚本语言,如JavaScript或PHP)不同.关键在于,根据我的知识,当精度很重要时,浮点数是不可靠的,而我想到的最简单的例子之一就是总和:

float(0.1) + float(0.2)
Run Code Online (Sandbox Code Playgroud)

不同于人们所期望的不是float(0.3),但float(0.30000000000000004)由于"幕后问题".所以,在我的虚拟Java代码中,我写道:

float wrongResult = 0.1f + 0.2f;
if (wrongResult != 0.3f) {
    System.out.println("float sucks");
}
else {
    System.out.println("float works");
}

double rightResult = 0.1 + 0.2;
if (rightResult != 0.3) {
    System.out.println("double sucks");
}
else {
    System.out.println("double works");
} 
Run Code Online (Sandbox Code Playgroud)

但输出令人惊讶:

float works
double sucks
Run Code Online (Sandbox Code Playgroud)

这让我很疯狂,因为double是64位类型而float只是32位类型,所以我期望相反的结果,因为double应该更精确.所以我的困境是:为什么像Python,PHP和Javascript这样的脚本语言在某种程度上表现得像Java和C#这样的编译语言表现不同?

Joh*_*anL 9

脚本语言和Java/C#之间没有区别.但是,float和之间存在差异double.一个小小的混淆来自这样一个事实:在脚本语言中(至少在Python中),底层类型float通常具有64位精度(即doubleJava中的a).因此,对于不同的行为,原因是舍入后的最接近的值将不相同,如下所示:

fl64(.1) == 0.10000000000000001
fl64(.2) == 0.20000000000000001
fl64(.3) == 0.29999999999999999
fl64(.1) + fl64(.2) == 0.30000000000000004

fl32(.1) == 0.1
fl32(.2) == 0.2
fl32(.3) == 0.30000001
fl32(.1) + fl32(.2) == 0.30000001
Run Code Online (Sandbox Code Playgroud)

因此,精度较低(32位)恰好就是这样0.1 + 0.2 == 0.3.然而,这不是一般结果,对于许多其他数字,这将不成立.因此,浮子对于精确的精确度仍然是不可靠的.