Java 浮点数和整数之间的双射保持顺序

问题描述 投票:0回答:7
Java 中的

int

float
 都是 32 位大小的值。是否可以编写一对函数

int toInt(float f); float toFloat(int n);

这样,如果

f1

f2
 是任意 
float
 非 NaN 值,并且 i1 和 i2 是任意 
int
 值: 

  • f1 < f2
    当且仅当
    toInt(f1) < toInt(f2)
    
    
  • f1 > f2
    当且仅当
    toInt(f1) > toInt(f2)
    
    
  • f1 == f2
    当且仅当
    toInt(f1) == toInt(f2)
    
    
  • toInt(toFloat(i1) == i1
    
    
  • toFloat(toInt(f1)) == f1
    
    
编辑:我已经编辑了问题以排除浮点数的 NaN 值,感谢澄清这些值会发生什么的答案。

java casting int
7个回答
7
投票
是的。

IEEE 浮点数 和双精度数的排列方式使您可以通过对原始二进制表示进行 无符号 比较来比较它们。从浮点到原始整数以及返回的函数是java.lang.Float.floatToIntBitsjava.lang.Float.intBitsToFloat。这些函数是处理器内在函数,因此它们的成本极低。

长打和双打也是如此。这里的转换函数是

java.lang.Double.doubleToLongBitsjava.lang.Double.longBitsToDouble.

请注意,如果您想对整数使用正常的

signed 比较,除了转换为整数之外,您还必须进行一些额外的转换。

此规则的唯一例外是 NaN,它无论如何都不允许全排序。


1
投票
你可以使用

int n = Float.floatToRawIntBits(f); float f2 = Float.intBitToFloat(n); int n2 = Float.floatToRawIntBits(f2); assert n == n2; // always assert f == f2 || Float.isNaN(f);

作为

int

 的原始位与原始 
float
 具有相同的排序顺序,但与 
NaN
 值不可比较的 
float
 值除外,具有作为 
int
 的值

注意:

NaN

有多个值,它们彼此不等于
float

    


1
投票
不,你不能

有 2^32 种可能的 int 值,所有这些值都是不同的。 然而,e 的浮点数少于 2^32; IE。 7FF0000000000001 到 7FF7FFFFFFFFFFFF 代表 NaN,

因此,您拥有的整数多于浮点数,并且无法将它们清楚地相互映射,因为

toFloat(i1)

无法为每个整数生成不同的浮点数


1
投票
我明白你在说什么。起初我对你的问题有不同的解释。正如其他人提到的:是的。使用

herehere描述的文章来解释为什么我们应该使用@Peter Lawrey描述的方法来比较整数和浮点数之间的底层位模式


1
投票
Rüdiger Klaehn 的回答给出了正常情况,但缺少一些细节。双射仅存在于

nice和clean浮点数的域中。

注意:IEEE 浮点数的表示形式为

sign_bit(1 bit) exponent(8 bits) sinificand(23 bits)

,在 
clean
 情况下其值为:
(-1)<sup>sign</sup> * 2<sup>exp</sup> * significand。事实上,23位代表实际有效数的小数部分,整数部分为1。

对于

0 < exp < 255

 (对应于 
normal not null floats )作为无符号字节来说一切都很好,并且在该域中你有一个双射。

对于

exp == 255

,您拥有无限值 
significand == 0
 以及 
significand != 0
 的所有 NaN - 好吧,您明确排除了它们。

但是对于

exp == 0

 来说,仍然有一些奇怪的事情:当 
significand == 0
 时,你有 +0 和 -0。我不确定他们是否被认为是平等的。如果有人知道,请随时编辑帖子。但作为整数值,它们当然会有所不同。

exp == 0

significand != 0
 时,你会发现非规范化数字......虽然不相等,但会被转换为不为 0 的最小数字的 0。

因此,如果您想要双射,请仅使用具有

0 < exp < 255<正常

 数字,并避免使用 NaN、无穷大、0 和非正规数,因为这些数字
很奇怪。 参考资料:

    IEEE 浮点
  • 单精度浮点格式
  • 非正规数

0
投票
是不可能的,请参阅
这个答案

了解更多信息。如果您确实想要近似相等检查,则需要包含增量。


0
投票

public static long toLong(float v) { long bits = Integer.toUnsignedLong(Float.floatToIntBits(v)); return Math.copySign(1, v) < 0 ? -bits : bits; }

通过迭代每个非 nan 浮点值,应该需要不到一分钟的时间来确认这是否有效:

public static void main(String[] args) { float current = Float.NEGATIVE_INFINITY; while (current != Float.POSITIVE_INFINITY) { float next = Math.nextUp(current); long curLong = toLong(current); long nextLong = toLong(next); if (curLong >= nextLong) { throw new RuntimeException(curLong + " is greater than " + nextLong + " representations of " + current + " and " + next); } current = next; } System.out.println("Reached " + current); }

© www.soinside.com 2019 - 2024. All rights reserved.