Java 比较两个相同的;字面上的;相等的浮点数错了吗?

Java 比较两个相同的;字面上的;相等的浮点数错了吗?,java,floating-point,precision,floating-accuracy,ieee-754,Java,Floating Point,Precision,Floating Accuracy,Ieee 754,这个问题与语言无关,但代码是用Java编写的 我们都听说比较浮点数是否相等通常是错误的。但如果我想比较两个完全相同的文字浮点值(或表示转换为浮点值的完全相同文字值的字符串),该怎么办 我很确定这些数字是完全相等的(因为它们在二进制中必须相等,所以完全相同的东西怎么会产生两个不同的二进制数?!),但我想确定一下 案例1: void test1() { float f1 = 4.7; float f2 = 4.7; print(f1 == f2); } 案例2: class

这个问题与语言无关,但代码是用Java编写的


我们都听说比较浮点数是否相等通常是错误的。但如果我想比较两个完全相同的文字浮点值(或表示转换为浮点值的完全相同文字值的字符串),该怎么办

我很确定这些数字是完全相等的(因为它们在二进制中必须相等,所以完全相同的东西怎么会产生两个不同的二进制数?!),但我想确定一下

案例1:

void test1() {
    float f1 = 4.7;
    float f2 = 4.7;
    print(f1 == f2);
}
案例2:

class Movie {
    String rating; // for some reason the type is String
}

在这两种情况下,表达式
f1==f2
应导致
true
。我说得对吗?如果它们具有相同的文字浮点值或字符串值,我是否可以安全地比较
评级是否相等?

是。相同的编译时常量的计算结果是一致的


如果你想一想,它们一定是一样的,因为只有一个编译器,它会将文本决定性地转换为它们的浮点表示。

是的。相同的编译时常量的计算结果是一致的


如果你仔细想想,它们一定是一样的,因为只有一个编译器,它会将文本决定性地转换为它们的浮点表示。

有一条经验法则,你应该应用于所有编程经验法则(经验法则?):

它们过于简单化,如果推进得太远,将导致愚蠢的决策。如果你不能完全理解经验法则背后的意图,你就会陷入困境。也许经验法则仍然是一个净积极因素(不假思索地应用它会改善事情,而不是让事情变得更糟),但它会造成损害,而且无论如何它都不能在辩论中用作论据

因此,考虑到这一点,显然,提出这个问题没有意义:

“假设存在“不使用==比较浮动”的经验法则,那么它总是不好的吗?”

答案是非常明显的:嗯,不。这并不总是坏事,因为经验法则基本上是根据定义的,如果不是根据常识的话,永远不会适用

那么让我们把它分解一下

为什么有一个经验法则,你不应该==比较浮动

您的问题表明您已经知道这一点:这是因为对IEEE754概念(如java的
double
float
等)表示的浮点进行任何数学运算都是不精确的(与java的
BigDecimal
等概念相比,这是精确的*)

当你面对一条经验法则时,当你摸索经验法则存在的原因并意识到它不适用于你的场景时,做你应该做的事情:完全忽略它

也许你的问题可以归结为:我想我摸索着经验法则,但也许我遗漏了什么;除了不适用于这种情况的“浮点数学引入了小偏差,导致混乱==比较”,还有其他我不知道的原因吗

在这种情况下,我的答案是:据我所知,没有


*)但是BigDecimal有它自己的相等问题,例如:两个BigDecimal对象是否精确地表示同一个数学数,但配置为以不同的比例渲染“相等”?这取决于您的观点是它们是数字还是表示精确小数点的对象,以及一些元属性,包括如何渲染它,以及在明确要求时如何进行取整。值得一提的是,
等于
BD的实现,它必须做出一个索菲式的选择,并在平等含义的两种同样有效的解释之间进行选择,选择“我代表一个数字”,而不是“我代表一个数元以及一堆元数据”。所有JPA/Hibernate堆栈中都存在相同的sophie选择:JPA对象是否表示“数据库中的一行”(因此,相等仅由主键值定义,如果尚未保存,两个对象不能相等,甚至不能相等,除非具有相同的引用标识),或者它是否表示该行表示的内容,例如,一名学生,而不是“数据库中代表一名学生的一行”,在这种情况下,unid是一个与身份无关的字段,而所有其他字段(姓名、生日、社会保险号等)都是。平等是很难做到的。

有一条经验法则,您应该将其应用于所有编程经验法则(经验法则?):

它们过于简单化,如果推进得太远,将导致愚蠢的决策。如果你不能完全理解经验法则背后的意图,你就会陷入困境。也许经验法则仍然是一个净积极因素(不假思索地应用它会改善事情,而不是让事情变得更糟),但它会造成损害,而且无论如何它都不能在辩论中用作论据

因此,考虑到这一点,显然,提出这个问题没有意义:

“假设存在“不使用==比较浮动”的经验法则,那么它总是不好的吗?”

答案是非常明显的:嗯,不。这并不总是坏事,因为经验法则基本上是根据定义的,如果不是根据常识的话,永远不会适用

那么让我们把它分解一下

为什么有一个经验法则,你不应该==比较浮动

您的问题表明您已经知道这一点:这是因为对IEEE754概念(如java的
double
float
等)表示的浮点进行任何数学运算都是不精确的(与java的
BigDecimal
等概念相比,这是精确的*)

当你面对一条经验法则时,当你摸索经验法则存在的原因并意识到它不适用于你的场景时,做你应该做的事情:完全忽略它

也许你的问题可以归结为:我想我摸索着经验法则,但也许我遗漏了什么;除了"浮动p"之外,
void test2() {
    movie1.rating = "4.7";
    movie2.rating = "4.7";

    float f1 = Float.parse(movie1.rating);
    float f2 = Float.parse(movie2.rating);

    print(f1 == f2);
}
1,000,000,001
1.000,000,000