【问题标题】:What is precision of double/float comparison (relation operator) with integral types?整数类型的双精度/浮点比较(关系运算符)的精度是多少?
【发布时间】:2018-03-11 20:44:36
【问题描述】:
整数类型的双精度/浮点比较(关系运算符)的精度是多少?
我了解不建议在任何比较中使用浮点数。但到目前为止,这个操作是允许的,这里有一个问题:
int x = 90;
float y = 90.00_001f;
if (x < y) {
System.out.println("it works!"); // gets printed
}
// now just add one zero to lessen the precision a bit...
int x = 90;
float y = 90.000_001f;
if (x < y) {
System.out.println("it works!"); // not printed
}
【问题讨论】:
标签:
java
floating-point
integer
comparison
【解决方案1】:
其他答案都是正确的,这里不再赘述。
我想补充的是,关于将 == 视为等价关系的另一个潜在惊喜,这通常意味着关联性:
(a == b) and (b == c) => (a == c)
但如果你尝试这个 sn-p,例如在 https://repl.it 中:
class Main {
public static void main(String[] args) {
int i=16777217;
float f=16777216.0f;
double d=16777216.0;
if(i == f) {
System.out.println("i == f");
}
if(d == f) {
System.out.println("d == f");
}
if(i == d) {
System.out.println("i == d");
}
}
}
令人惊讶的是i==f 和f==d 但not(i==d)...
这是因为在编写 i==f 时,会发生隐式转换 float(i)==f,并且这种转换可能会导致精度降低,因为 int 最多需要 31 位精度,而 float 最多提供 24 位。
这可能会有所不同,如果你看看 Lisp、Scheme 或最近的 Squeak/Pharo Smalltalk 是如何处理比较的,你会发现它们在乎准确性......
从http://www.lispworks.com/documentation/lcl50/aug/aug-170.html提取
一般来说,当运算同时涉及有理数和浮点参数时,首先将有理数转换为浮点格式,然后再进行运算。
这种转换过程称为浮点传染。但是,对于数值相等比较,使用有理算术比较参数以确保相等(或不等)关系的传递性。
【解决方案3】:
这里的问题不在于与整数的比较,而是float 本身的精度。
在指定浮点(或双精度)字面量时,可以指定任意多的小数位;但这并不意味着编译代码时会保留精度。
例如,以下所有值都具有相同的值:
90.f
90.000_001f
90.00000000000000000000000000000000000000000000000000000000000000001f
Ideone demo
所以第二次比较失败的原因是90.000_001f等于90.f;这等于将90 扩大到float 的值。