我刚开始学习 Kotlin,在基本类型的文档中遇到了一个奇怪的句子:
-0.0被视为小于 0.0
我知道它们的值在补码中不会相同,但我不知道如何在代码中使用它。
不遵循 IEEE 754 标准的擦除浮点比较的主要目的是,当您在集合中使用浮点数并作为排序键时,您不希望根据标准相等的值相互混合。例如,您不希望将-0.0
和0.0
混合为映射中的键(您可能需要为这些键使用两个不同的值)。
同样,您希望地图将NaN
与自身匹配,尽管标准规定NaN
!=NaN
.
而且,当您对一组项目进行排序时,您希望NaN
与其他数字正确排序,即使标准说它与其他元素无法比拟(遵循此处的标准甚至可能会破坏排序算法)。
请注意,仅当对象在静态上不属于浮点类型时,这些规则才适用,而浮点类型实际上与通用用例和集合匹配。相反,数学用例通常直接使用数字类型(而不是将它们擦除为Any
或类型参数),因此应用 IEEE 754 规则。
我也发现了这句话,这令人费解。它实际上与零有两个表示形式的事实关系不大,因为(有人可能会认为)理论上这应该隐藏在实现中,以便 -0.0 == +0.0 为真(可能不是 ===),同样 -0.0 <+0.0 和 +0.0 <-0.0 都是假的)。
但是,声明 -0 <+0 有一些很好的理由,尽管通常这些理由非常模糊。IEEE 754标准规定了应该从什么返回,并且还具有用于舍入模式等的剩余(通常可设置,但也通常是全局)控制开关,以及(IIRC)还用于控制-0.0<+0.0或==。
我敢肯定,Kotlin 的人已经彻底考虑过这一点(<- 绕口令),因为如果没有大量的思考和经验,没有人会以这种方式设计语言功能。我可以想象程序员在某些情况下对此感到非常困惑(例如,在多项式中找到虚假的额外根等),但如果程序员有足够的IEEE意识,并且了解区别在何时何地出现,似乎它不应该引起太多问题(除了跳过那部分文档的程序员!
当然,程序员必须格外小心地在浮点上使用相等式,但直到现在我总是认为"如果(!!x) 返回 1.0/x"或多或少是安全的(考虑到 IEEE 对四舍五入、溢出等的仔细关注)。也许这在 Kotlin 文档的其他地方有讨论;我仍然对这个功能感到有点不安。
我完全不明白上面的第一个答案,尽管我承认我是 Kotlin 的新手。
我不知道"擦除的浮点比较"是什么意思,但我假设这意味着 -0.0 != +0.0 的决定。我认为这是一个执行决定,而不是一个擦除。
我也完全不明白最后一段是什么意思。根据类型是否静态可确定来更改类型的相等语义是荒谬的。我无法猜测 Kotlin 设计师的想法,但它不可能是这样的;我只是完全不明白那段话是怎么回事。
此外,违反 IEEE 数字以允许浮动映射键,或提供额外的哨兵、标志或键值,是一种奇怪的优先级倒置。这就是 NaN 的用途。对如此广泛使用的标准的非凡违反需要非凡的动机,而上面的第一个答案似乎错过了那条船。
如果您需要玩这种奇怪的游戏,最好使用底层的 32、64 或 128 位位串作为密钥。在做实时数值处理的 45 年里,我什至从未想过用浮点数索引地图,尽管我实际上可以想象它(但不会改变标准以适应这样的笨拙)。
也许我出去吃午饭,但这里似乎在某个地方存在严重的脱节。