首页 > 解决方案 > 为什么 Oracle 声称 java.util.Random.nextFloat() 生成 2^24 种可能性而不是 2^23?

问题描述

根据java.util.Random的文档,Java 类实现nextFloatnext(24) / ((float)(1 << 24))(即一个 24 位的随机非负整数除以 2 24)。该文档声称可以返回所有 2 24 个可能的值。它们介于 0(包括)和 1(不包括)之间。然而,我不认为这是真的。

首先,请注意,根据 IEC 559 (IEEE 754) 标准,float有 23 个小数位。但是存在一个值为 1 的隐式前导位(在二进制点的左侧),除非指数以全零存储。因此,确实有 2 24个类型值float介于 0(包括 - 不包括负零)和 1(不包括)之间,但是这些数字中恰好有一半是次正规的(指数中的所有位都是 0 ),这使得它们都小于 2 -126。因此,这些数字都不能由实现生成。这是因为它们都严格小于实现中使用的 2 -24

的布局float可以在Single-precision floating-point format中找到。

那么我错过了什么?

标签: javarandomfloating-point

解决方案


在区间 [+0, 1) 中,有 127•2 23个可表示的值float,而不是 2 24。从 0 到 126(含)的指​​数编码字段的每种组合都有一个,有效数字编码字段中的每个值都是 23 位。

m •2 -24形式的每个值,0 ≤ m < 2 24,都是可表示的。这种形式的最小非零值是 2 −24,它用指数代码 103 和有效代码代码 0 表示。数学指数是代码 103 减去偏差 127,等于 −24,数学有效数为 1。

对于除零以外的任何此类m ,令b为其前 1 位的位置编号(从 0 开始编号为低位)。然后m •2 -24被编码为b +103float的指数代码和m •2 24- b -2 24的有效数字代码。对于m = 0,它被编码为全零位。

这种形式的数字都不是次常的。


推荐阅读