JDK在
ThreadLocalRandom
中有一个随机方法:
nextDouble(startInclusive, endExclusive)
但没有
float
版本。这里我想要浮动版本,这是我的实现:
public static float nextFloat(float startInclusive, float endExclusive) {
return (float) nextDouble(startInclusive, endExclusive);
}
我知道浮点数在将 double 转换为 float 时存在精度问题。那么,结果有可能是 float value < startInclusive or >= endExclusive 吗?以及如何解决?
事实上,您当前的实现可能会输出等于
endExclusive
的浮点数。假设 next double
返回 d
,它小于 endExclusive
,但由 d
表示的最接近 float
的值仍可能是 endExclusive
。
在现代版本的 JDK 中,存在
nextFloat
,它采用下界和上限。如果您使用的是旧版本,您可以看看新版本中的nextFloat
是如何实现的,然后自己做同样的事情。
使用 OpenJDK 主分支中的 RandomSupport.java 中的代码,您可以编写这样一个助手:
public static float nextFloat(Random random, float origin, float bound) {
if (!(Float.NEGATIVE_INFINITY < origin && origin < bound &&
bound < Float.POSITIVE_INFINITY)) {
throw new IllegalArgumentException("Invalid range");
}
float r = random.nextFloat();
if (bound - origin < Float.POSITIVE_INFINITY) {
r = r * (bound - origin) + origin;
} else {
float halfOrigin = 0.5f * origin;
r = (r * (0.5f * bound - halfOrigin) + halfOrigin) * 2.0f;
}
if (r >= bound)
r = Math.nextDown(bound);
return r;
}
这使用了无参数的
nextFloat
,它已经存在很长时间了。它返回一个 0 到 1 之间的随机浮点数,代码简单地将 0~1 范围线性映射到我们想要的范围。这个过程也有可能生成一个大于或等于上限的数字,在这种情况下,JDK 似乎只使用小于 bound
(Math.nextDown
) 的最大浮点数。