简体   繁体   English

如何生成与比例无关的随机浮点数?

[英]How to generate scale-independent random floating point numbers?

I want to generate what I'm choosing to call "arbitrary" positive floating-point numbers; 我想生成我选择称之为“任意”正浮点数的东西; that is, random numbers which are independent of scale (in other words, numbers whose logarithms are uniformly distributed). 也就是说,随机数与尺度无关(换句话说,是对数均匀分布的数字)。 I'm not much of a mathematician, so for all I know there may be another name for what I'm after. 我不是一个数学家,所以我知道我可能会有另一个名字。

Here's my initial, naïve solution: 这是我最初的,天真的解决方案:

import sys
import random

def arbitrary(min=sys.float_info.min_10_exp, max=sys.float_info.max_10_exp):
    return 10 ** random.uniform(min, max)

It strikes me that this is probably not ideal: for one thing, I imagine that there might be some interaction between the limited precision of random.uniform() and the floating point representation itself that would cause bunching and gaps in the expected output at higher orders of magnitude. 令我感到random.uniform()是,这可能并不理想:首先,我认为random.uniform()的有限精度与浮点表示本身之间可能存在一些相互作用,这会导致预期输出中的聚束和间隙更高数量级。

Is there a better approach? 有更好的方法吗? Would it make more sense to just produce a string of random bits and then turn that into the floating point number they represent? 仅生成一串随机位然后将其转换为它们所代表的浮点数会更有意义吗?

EDIT : As pointed out by Oli Charlesworth in the comments, the "convert random bits to a float" idea doesn't do what I want (which is a uniform distribution of log(n)). 编辑 :正如Oli Charlesworth在评论中所指出的那样,“将随机位转换为浮点数”的想法并没有达到我想要的效果(这是log(n)的均匀分布)。

You are correct that your approach doesn't return some numbers. 你是正确的,你的方法不会返回一些数字。 For example, there is no floating-point number between 1.0 and 1.0000000000000002 , but 10**1.0000000000000002 is 10.000000000000005 , and there are two numbers between 10.0 and 10.000000000000005 : 10.000000000000002 and 10.000000000000004 . 例如, 1.01.0000000000000002之间没有浮点数,但10**1.000000000000000210.000000000000005 ,并且10.010.000000000000005之间有两个数字: 10.00000000000000210.000000000000004 Those two numbers will never be returned by your algorithm. 算法永远不会返回这两个数字。

But you can cheat and use Decimal to exponentiate with greater precision: 但你可以作弊并使用Decimal以更高的精度取幂:

>>> float(10 ** Decimal('1'))
10.0
>>> float(10 ** Decimal('1.0000000000000001'))
10.000000000000002
>>> float(10 ** Decimal('1.00000000000000015'))
10.000000000000004
>>> float(10 ** Decimal('1.0000000000000002'))
10.000000000000005

So, arbitrary needs to generate random Decimal exponents of sufficient precision and use them as exponents. 因此, arbitrary需要生成足够精度的随机Decimal指数并将它们用作指数。 Assuming 64 binary digits is enough precision for the exponent, the code would look like this: 假设64个二进制数字对于指数是足够的精度,代码将如下所示:

import sys, random
from decimal import Decimal

def _random_decimal(minval, maxval, added_prec):
    # generate a Decimal in the range [minval, maxval) with the
    # precision of additional ADDED_PREC binary digits
    rangelen = maxval - minval
    denom = rangelen << added_prec
    return minval + Decimal(rangelen) * random.randrange(denom) / denom

def arbitrary():
    min_exp = sys.float_info.min_exp - sys.float_info.mant_dig
    max_exp = sys.float_info.max_exp
    return float(2 ** _random_decimal(min_exp, max_exp, 64))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM