How to create scale independent random floating point numbers?

I want to generate what I choose to call “arbitrary” positive floating point numbers; that is, random numbers that are independent of scale (in other words, numbers whose logarithms are evenly distributed). I am not a very mathematician, so as far as I know, there may be a different name for what I need.

Here is my initial naive 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 seems to me that this is probably not ideal: firstly, I believe that there may be some kind of interaction between the limited precision of random.uniform() and the idea of ​​a floating point itself, which will lead to grouping and spaces in the expected output on higher orders.

Is there a better approach? Would it be wiser to just create a string of random bits and then turn that into the floating point number that they represent?

EDIT . As Oli Charlworth noted in the comments, the idea of ​​"converting random bits to float" does not do what I want (which is a uniform distribution of log (n)).

+4
source share
1 answer

You are right that your approach does not return some numbers. For example, there is no floating point number between 1.0 and 1.0000000000000002 , but 10**1.0000000000000002 10.000000000000005 is 10.000000000000005 , and between 10.0 and 10.000000000000005 there are two numbers: 10.000000000000002 and 10.000000000000004 . These two numbers will never be returned by your algorithm.

But you can spoof and use Decimal for higher exponentiality:

 >>> 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 

Therefore, arbitrary should generate random Decimal metrics with sufficient accuracy and use them as metrics. Assuming 64 bits is enough for an exponent, the code would look like this:

 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)) 
+1
source

Source: https://habr.com/ru/post/1490061/


All Articles