1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
#############################################################################
##
## realrandom.gi IO package
## by Max Neunhoeffer
##
## Copyright (C) 2006-2010 by Max Neunhoeffer
## This file is free software, see license information at the end.
##
## Code for "real" random sources using /dev/random
##
#############################################################################
InstallMethod( Init, "for a real random source",
[IsRealRandomSource,IsString], 1,
function( r, type )
local f;
if type <> "random" and type <> "urandom" then
Error("seed must be \"random\" or \"urandom\"");
fi;
if type = "random" then
f := IO_File("/dev/random",128); # Use smaller buffer size
else
f := IO_File("/dev/urandom",1024); # Use medium buffer size
fi;
if f = fail then return fail; fi;
r!.file := f;
r!.type := type;
return r;
end );
InstallMethod( State, "for a real random source",
[IsRealRandomSource],
function(r)
return fail;
end );
InstallMethod( Reset, "for a real random source",
[IsRealRandomSource],
function(r)
return;
end );
InstallMethod( Reset, "for a real random source and an object",
[IsRealRandomSource,IsObject],
function(r,o)
return;
end );
InstallMethod( Random, "for a real random source and two integers",
[ IsRealRandomSource, IsInt, IsInt ],
function( r, f, t )
local c,d,h,i,l,q,s;
d := t-f; # we need d+1 different outcomes from [0..d]
if d <= 0 then return fail; fi;
l := (Log2Int(d)+1); # now 2^l >= d
l := (l+7) - (l+7) mod 8; # this rounds up to a multiple of 8, still 2^l>=d
q := QuoInt(2^l,d+1); # now q*(d+1) <= 2^l < (q+1)*(d+1)
# thus for 0 <= x < 2^l
# we have 0 <= x/q <= d+1 <= 2^l/q
# Thus if we do QuoInt(x,q) we get something
# between 0 and d inclusively, and if x is
# evenly distributed in [0..2^l-1], all values
# between 0 and d occur equally often
repeat
s := IO_ReadBlock(r!.file,l/8); # note that l is divisible by 8
h := "";
for c in s do Append(h,HexStringInt(INT_CHAR(c))); od;
i := IntHexString(h); # this is now between 0 and 2^l-1 inclusively
i := QuoInt(i,q);
until i <= d;
return f+i;
end );
InstallMethod( Random, "for a real random source and a list",
[ IsRealRandomSource, IsList ],
function( r, l )
local nr;
repeat
nr := Random(r,1,Length(l));
until IsBound(l[nr]);
return l[nr];
end );
InstallMethod( ViewObj, "for a real random source",
[IsRealRandomSource],
function(rs)
Print("<a real random source>");
end );
InstallMethod( IO_Pickle, "for a real random source",
[IsFile, IsRealRandomSource],
function(f,rs)
if IO_Write(f,"RSRE") = fail then return IO_Error; fi;
if IO_Pickle(f,rs!.type) = IO_Error then return IO_Error; fi;
return IO_OK;
end );
IO_Unpicklers.RSRE := function(f)
local t;
t := IO_Unpickle(f);
if t = IO_Error then return IO_Error; fi;
return RandomSource(IsRealRandomSource,t);
end;
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
##
|