如何将浮点数剪切到一个下限以下?

7

numpy.random.uniform()这样的函数返回两个边界之间的浮点数值,包括第一个边界但是不包括最高边界。也就是说,numpy.random.uniform(0,1)可能产生0,但永远不会产生1。

我正在使用一个处理这些数字的函数,但有时会返回超出范围的结果。我可以使用numpy.clip()将超出范围的值裁剪到0-1,但不幸的是,这个限制是包括最高数的。

如何在Python中指定“比1略小的数字”?


如果相信数学,你是做不到的。 - Ignacio Vazquez-Abrams
2
在大多数系统中,都有一个“epsilon”的概念,它是最小的增量。 - Keith Nicholas
1
我不认为我在悖论(或火拼)的领域里。你是说 numpy.random.uniform(0,1) 有时会返回一个等于1的数字吗?如果是这样,那好吧,我并不在乎这个悖论,但我希望我的修改后被削减的数字能够保证与原始数字处于相同的范围内。 - mattdm
3
我认为wim指的是数学上的实数0.9999...(循环),其实就是精确等于1的概念。浮点数不是实数,因此与您的问题无关。但是,我将利用这个机会提到uniform(x,y)可能(极其罕见!)给您与“y”完全相等的结果的情况。虽然在uniform(0,1)中不应该出现这种情况,但在其他情况下,用于重新调整底层[0,1)随机数到您的界限的浮点算术有时可能会恰好给出“y”。 - Robert Kern
感谢@RobertKern。我注意到Python的“random”文档中提到了这一点;NumPy文档也应该更新并包含该免责声明。 - mattdm
显示剩余2条评论
3个回答

7

如果你正在使用numpy,那么可以简单地使用numpy.nextafter函数:

>>> import numpy
>>> numpy.nextafter(1, 0)
0.99999999999999989

请注意(至少对我来说):
>>> import sys
>>> 1-sys.float_info.epsilon
0.9999999999999998
>>> numpy.nextafter(1, 0) - (1-sys.float_info.epsilon)
1.1102230246251565e-16
>>> numpy.nextafter(1, 0) > (1-sys.float_info.epsilon)
True

顺便提一下,支持@Robert Kern的观点,有时候random.uniform会包括上限,而不仅仅是(0,1)之外的某些输入:

>>> import random, numpy
>>> numpy.nextafter(0,1)
4.9406564584124654e-324
>>> random.uniform(0, numpy.nextafter(0,1))
0.0
>>> random.uniform(0, numpy.nextafter(0,1))
0.0
>>> random.uniform(0, numpy.nextafter(0,1))
4.9406564584124654e-324

[我认为也许有更好的方法来解决这个问题。]


为什么 numpy.nextafter(1, 0) == (1-sys.float_info.epsilon) 不成立呢?是因为浮点数的密度取决于其大小吗? - wim
@wim:没错。1+epsilon/2 = 1,但是1-eps/2 = nextafter(1,0)。 - DSM

3

Python的sys模块提供了一个名为float_info的结构体,其中有一个epsilon属性,定义为:

1和比1大但仍可表示为浮点数的最小值之间的差异

所以我认为类似以下语句就行:

def clip(num):
    if(num >= 1):
        return 1 - sys.float_info.epsilon
    return num

这应该能解决问题。虽然通常情况下这是不好的,可能有很多理由为什么你永远不应该尝试这样做。

编辑 我刚刚发现了其中一个原因——实现。虽然CPython会按照你的期望执行,但我的首选是IronPython,它不会(虽然这是个bug)。你已经被警告了!


那么...有没有一种不是通常糟糕的方法? - mattdm
1
这真的取决于为什么你需要将函数放在[0,1)中。你想忽略大于等于1的值吗?你想将这些值包括在1-eps中吗?谁会使用这些值,为什么那个人需要它们在[0,1)中?你说存在一个返回[0,1)的库函数u。然后你对这些数字进行f(u())操作并返回[0,inf),但是想要返回[0,1)...为什么?可能有一个h(f(u)),也许我们应该关注h。 :) - Gleno

2

在大多数实际情况下,您不需要无限小,可以进行近似。因此,对于您的示例,我将使用0.9999999而不是1.0。


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