in reply to Re^4: inclusive rand
in thread inclusive rand

> It will always be less precise, i.e. choosing among fewer numbers. No?

even if you don't want to use a self defined precission you could try this

perl -Mposix -E" say rand(1+1/2**47) for 1..20"

So why 47?

Just try and error on my system

C:\Windows\system32>perl -E" say 1+1/2**47;" + 1.00000000000001 C:\Windows\system32>perl -E" say 1+1/2**48;" 1

I'm too lazy to figure out how exactly the limits of the mantissa is used internally and where the caveats are.

And taking the rounding errors in these into assumption this shouldn't matter much. (as BUK mentioned under windows before 5.20 rand is limted to 15 bits only.)

The practical value of this is too small to justify more elaboration.

update

or alternatively to avoid floats and rounding errors

C:\Windows\system32>perl -E"$r=int rand(1e15+1); say $r==1e15 ? 1 : sp +rintf '0.%015s', $r" 0.176483154296875

Cheers Rolf
(addicted to the Perl Programming Language and ☆☆☆☆ :)
Je suis Charlie!

Replies are listed 'Best First'.
Re^6: inclusive rand
by pryrt (Abbot) on Mar 13, 2017 at 16:06 UTC

    The limit of the mantissa is the ULP. For a double-precision float typically used in perl, it's 2**-52 times the main power of two for the number:

    perl -MData::IEEE754::Tools=:all -le"$,=qq(\t); map { print $_, ulp($_ +) } @ARGV" 0.25 0.4 0.5 0.6 0.9 1 1.9 2 0.25 5.55111512312578e-017 0.4 5.55111512312578e-017 0.5 1.11022302462516e-016 0.6 1.11022302462516e-016 0.9 1.11022302462516e-016 1 2.22044604925031e-016 1.9 2.22044604925031e-016 2 4.44089209850063e-016

    This can also be seen in your 1+1/2**x by printing the underlying IEEE754, or by using a powers-of-two representation of the float, or by always using %.16f

    perl -MData::IEEE754::Tools=:all -e"printf qq(%-3d %-32.32s 0x%-16s %. +16f %s\n), $_, 1+1/2**$_, hexstr754_from_double(1+1/2**$_), 1+1/2**$_ +, to_dec_floatingpoint(1+1/2**$_) for @ARGV" 47 48 49 50 51 52 53 54 +55 56 47 1.00000000000001 0x3FF0000000000020 1.000000000000 +0071 +0d1.0000000000000071p+0000 48 1 0x3FF0000000000010 1.000000000000 +0036 +0d1.0000000000000036p+0000 49 1 0x3FF0000000000008 1.000000000000 +0018 +0d1.0000000000000018p+0000 50 1 0x3FF0000000000004 1.000000000000 +0009 +0d1.0000000000000009p+0000 51 1 0x3FF0000000000002 1.000000000000 +0004 +0d1.0000000000000004p+0000 52 1 0x3FF0000000000001 1.000000000000 +0002 +0d1.0000000000000002p+0000 53 1 0x3FF0000000000000 1.000000000000 +0000 +0d1.0000000000000000p+0000 54 1 0x3FF0000000000000 1.000000000000 +0000 +0d1.0000000000000000p+0000 55 1 0x3FF0000000000000 1.000000000000 +0000 +0d1.0000000000000000p+0000 56 1 0x3FF0000000000000 1.000000000000 +0000 +0d1.0000000000000000p+0000

    for numbers from 0.5 to 0.9999..., it's one better:

    perl -MData::IEEE754::Tools=:all -e"printf qq(%-3d %-32.32s 0x%-16s %. +16f %s\n), $_, 0.5+1/2**$_, hexstr754_from_double(0.5+1/2**$_), 0.5+1 +/2**$_, to_dec_floatingpoint(0.5+1/2**$_) for @ARGV" 47 48 49 50 51 5 +2 53 54 55 56 47 0.500000000000007 0x3FE0000000000040 0.500000000000 +0071 +0d1.0000000000000142p-0001 48 0.500000000000004 0x3FE0000000000020 0.500000000000 +0036 +0d1.0000000000000071p-0001 49 0.500000000000002 0x3FE0000000000010 0.500000000000 +0018 +0d1.0000000000000036p-0001 50 0.500000000000001 0x3FE0000000000008 0.500000000000 +0009 +0d1.0000000000000018p-0001 51 0.5 0x3FE0000000000004 0.500000000000 +0004 +0d1.0000000000000009p-0001 52 0.5 0x3FE0000000000002 0.500000000000 +0002 +0d1.0000000000000004p-0001 53 0.5 0x3FE0000000000001 0.500000000000 +0001 +0d1.0000000000000002p-0001 54 0.5 0x3FE0000000000000 0.500000000000 +0000 +0d1.0000000000000000p-0001 55 0.5 0x3FE0000000000000 0.500000000000 +0000 +0d1.0000000000000000p-0001 56 0.5 0x3FE0000000000000 0.500000000000 +0000 +0d1.0000000000000000p-0001 perl -MData::IEEE754::Tools=:all -e"printf qq(%-3d %-32.32s 0x%-16s %. +16f %s\n), $_, 1.0-1/2**$_, hexstr754_from_double(1-1/2**$_), 1-1/2** +$_, to_dec_floatingpoint(1-1/2**$_) for @ARGV" 47 48 49 50 51 52 53 5 +4 55 56 47 0.999999999999993 0x3FEFFFFFFFFFFFC0 0.999999999999 +9929 +0d1.9999999999999858p-0001 48 0.999999999999996 0x3FEFFFFFFFFFFFE0 0.999999999999 +9965 +0d1.9999999999999929p-0001 49 0.999999999999998 0x3FEFFFFFFFFFFFF0 0.999999999999 +9982 +0d1.9999999999999964p-0001 50 0.999999999999999 0x3FEFFFFFFFFFFFF8 0.999999999999 +9991 +0d1.9999999999999982p-0001 51 1 0x3FEFFFFFFFFFFFFC 0.999999999999 +9996 +0d1.9999999999999991p-0001 52 1 0x3FEFFFFFFFFFFFFE 0.999999999999 +9998 +0d1.9999999999999996p-0001 53 1 0x3FEFFFFFFFFFFFFF 0.999999999999 +9999 +0d1.9999999999999998p-0001 54 1 0x3FF0000000000000 1.000000000000 +0000 +0d1.0000000000000000p+0000 55 1 0x3FF0000000000000 1.000000000000 +0000 +0d1.0000000000000000p+0000 56 1 0x3FF0000000000000 1.000000000000 +0000 +0d1.0000000000000000p+0000
      thanks! :)

      I was aware about the 52 bits but too lazy to care about the DWIM rounding of Perl's number printing.

      And I don't think it really matters, there are far too many implementation details involved, to have a "reliable" random distribution in these dimensions.

      I still need to see the concrete requirements before investing in a better approach.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

Re^6: inclusive rand
by msh210 (Monk) on Mar 13, 2017 at 16:01 UTC

    Interesting ideas. Thanks!

    $_="msh210";$"=$\;@_=@{[split//,uc]}[2,0];$_="@_$\1";$\=$/;++$_[0]for$...1;print lc substr crypt($_,"@_"),1,6