Approximation of continuous distributions over a countable dense subset

123 Views Asked by At

The C++ programming language provides various random number generator for a specific distribution. For example, uniform distribution, normal distribution, and gamma distribution. The problem is, their domain is floating-point numbers. They are not really continuous!

I want the domain be some countable dense subset of $ℝ$. Say, $ℤ[½]$. The CDF over $ℤ[½]$ would be exactly the same to that over $ℝ$, regarding the monotonicity of a CDF.

Does this mean the distribution over $ℝ$ and that over $ℤ[½]$ (or any countable dense subset of $ℝ$, such as $ℚ$, $ℚ(e)$ or the computable numbers) are actually the same distribution? If so, does a deterministic algorithm that is an RNG for such distributions exist?

EDIT: I attempted to implement unifrom distribution over $[0,1) \cap ℤ[0.1]$. I have the following datatype that represents every computable number, in Haskell:

data Computable = Exact Rational | Inexact (Word -> Integer)

Exact labels every rational number. Inexact labels every Cauchy sequence whose limit is a computable number, like this (using lambda calculus):

$$ \text{Inexact}^{-1}(x) = \lambda n.\lfloor x \times 10^n \rceil $$

My implementation goes as (typeclass from System.Random):

instance Random Computable where
    random g = (Inexact $ \n -> let 
        (m, _) = randomR (0, 10 ^ n - 1) g
        in fromInteger m
        , snd (next g))

random is the unifrom distribution over $[0,1) \cap ℤ[0.1]$. It has g as an argument, which is a uniform RNG for arbitrary range of consecutive integers (randomR invokes it).

This RNG exploits that we will need a finite number (here n) of digits anyway. Though I'm unsure whether this should be considered cheating. Is this a valid implementation of uniform distribution over $[0,1)$?

EDIT 2: Here are some demonstrations of above implementation:

*Main> (randomIO :: IO Computable) >>= printf "%.10f\n"
0.3262603172
*Main> (randomIO :: IO Computable) >>= printf "%.10f\n"
0.3403967450
*Main> (randomIO :: IO Computable) >>= printf "%.100f\n"
0.9936260281178909626196416839104245487197517214117589458461696555250759264208337183187442235136905901
*Main> (randomIO :: IO Computable) >>= printf "%.100f\n"
0.5219990231813949459630646837792033907565924036630170372162638275931417874219363290725289123121942905
*Main> (randomIO :: IO Computable) >>= printf "%.100f\n"
0.7672947758151983385289808102387963496390862559263475666364045942540881408976619844216572264017856792
1

There are 1 best solutions below

0
On

Partial answer

The implemantation above has a major flaw. The sequence it outputs is not a Cauchy sequence, so it must not be labeled Inexact.

I fixed this problem this way:

instance Random Computable where
    random g = let
        (h, i) = split g
        getDigits gen = let
            (d, gen') = next gen
            in mod d 10 : getDigits gen'
        digits = getDigits h
        takeDigits n = getNum (reverse (take n digits))
        getNum [] = 0
        getNum (d:ds) = toInteger d + 10 * getNum ds
        in (Inexact (takeDigits . fromIntegral), i)

Now Inexact labels a Cauchy sequence.

Also, the domain of this RNG is indeed $[0,1]$ itself.