Java中的浮点数转换向下取整

4

我的代码中有一行类似于下面的代码:

float rand = (float) Math.random();

Math.random()返回一个double类型的数字,这个数字的值范围在>=0.0<1.0。不幸的是,如果这个double数字非常接近于1.0,那么上述强制转换可能会将rand设置为1.0f

有没有一种方式可以将double强制转换为float,使得当找不到精确相等的值时,它总是向下舍入到下一个浮点数值,而不是舍入到最接近的浮点数值?

我不是在寻求关于随机数生成器的建议,也不是像使用 if(rand == 1.0f) rand = 0.0f; 这样的解决方法。在我的情况下,该解决方案是解决问题的令人满意的方式,并且已经被实现了。我只是想找到一种“合适”的解决方案来进行这种数字转换。


你不能使用 nextFloat() 的原因是什么? - VGR
2个回答

1
我建议使用double而不是float。一般情况下,我发现唯一的缺点是在您拥有大量这些时才会发挥作用,因为存储要求更高,但在这种情况下似乎并非如此。如果您必须使用float,那么您已经尝试过的解决方案可能是可用的最佳解决方案。将double转换为float时精度丢失是一个根本性问题,它可能会给您1.0f。因此,强制浮点值处于所需范围内。然而,您不必在代码中频繁使用if语句,只需提供一个浮点随机函数即可为您完成繁重的工作。
float frandom() {
    float ret = 1.0f;
    while (ret == 1.0f)
        ret = (float) Math.random();
    return ret;
}

或者,根据你的示例:
float frandom() {
    float ret = (float) Math.random();
    if (ret == 1.0f)
        ret = 0.0f;
    return ret;
}

然后使用以下方式调用:
float rand = frandom();

这可能是Java(和其他语言)希望具有Javascript能力的地方,可以将代码“注入”到类型中,以便您可以将 frandom() 实现到静态 Math 领域。这样,您可以只需使用:
float rand = Math.frandom();

但是,不幸的是,这还不可能(据我所知,除非重新编译Java支持库,这似乎有点过度杀鸡)。


顺便提一下,如果你正在寻找小于1的最大浮点值,则为0.99999994(指数乘数为2-1,所有尾数位设置为1),因此您可以在上面的frandom()函数中使用它而不是0.0f
这是我一段时间前编写的一个方便小工具得出的结论,在处理IEEE754浮点值时非常有用。

是的,基本上这就是我已经拥有的。我想知道的问题是如何将双精度转换为浮点数,而不是四舍五入到最接近的可用值,而是向下舍入到下一个值。 - Numeron
1
0.1 应该是 1.0 吗? - user253751
小于1.0f的最大浮点数是0.99999994f,但四舍五入后小于1.0f的最大双精度浮点数大约为0.99999997,误差在千万分之一左右。这取决于所生成数字的期望分布。如果使用0.99999994作为限制,则最后一个值的概率只有分布更均匀时的一半。 - Pascal Cuoq
@Pascal,如果你是那种真正关心范围顶端或底端的小分布效应的人,那么你已经在使用不同的方法了 :-) - paxdiablo
@immibis,是的,本应该这样。已经修复了,谢谢。 - paxdiablo

1
如果您只想在rand==1.0f时四舍五入,则我支持@paxdiablo的回答。然而,听起来您可以始终进行四舍五入,并且只是想始终向下四舍五入。如果是这样:
float rand = Math.nextDown((float)Math.random());

来自javadoc:

nextDown(float f) 返回与f相邻且向负无穷方向的浮点值。

回复您的评论-好观点。为了避免这个问题,您可以简单地将语句包装在对Math.abs()的调用中,除非nextDown()的结果为负,否则不会产生影响。

float rand = Math.abs(Math.nextDown((float)Math.random()));

1
这是一个很有用的发现!但是如果Math.random()调用返回0.0,那就不好了,因为它会将其推到0以下。 - Numeron
我认为如果我使用类似于“if(doubleRand != floatRand) floatRand = Math.nextDown(floatRand);”的东西 - 这样只有在没有相等的等效值时才会丢弃一个值。 - Numeron
3
这是两个提议中较为丑陋的解决方案,令人失望的是它被选为了被接受的答案。这个解决方案存在与二次幂周围的别名问题(某些值无法获取,特别是形如 0x1.fffffepXX 的值,而二次幂则出现过多)。 - Pascal Cuoq
1
@paxdiablo 我同意 - 请看我上面的评论,我很确定在这里使用if会是更好的解决方案,我只是按照问题的要求(即不带if)来回答问题,同时也提出了一个解决方案。提出一个解决方案和回答一个非常特定的问题是两件完全不同的事情 - 这是后者。 - drew moore
1
@PascalCuoq 另一个答案并没有真正回答这个问题,我说过我对于我的特定问题不感兴趣 - 我想知道如何找到最接近但不超过 double 的浮点值。 - Numeron
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接