为什么 Kotlin 认为负零小于正零



我刚开始学习 Kotlin,在基本类型的文档中遇到了一个奇怪的句子:

-0.0

被视为小于 0.0

我知道它们的值在补码中不会相同,但我不知道如何在代码中使用它。

不遵循 IEEE 754 标准的擦除浮点比较的主要目的是,当您在集合中使用浮点数并作为排序键时,您不希望根据标准相等的值相互混合。例如,您不希望将-0.00.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 年里,我什至从未想过用浮点数索引地图,尽管我实际上可以想象它(但不会改变标准以适应这样的笨拙)。

也许我出去吃午饭,但这里似乎在某个地方存在严重的脱节。

最新更新