|
-
Dec 1st, 2023, 03:55 PM
#1
[RESOLVED] Random
Just for the heck of it I am buying this true random generator.
https://www.amazon.com/TrueRNG-V3-Ha.../dp/B01KR2JHTA
The device sends bytes over the comport that are random.
To get a head start I thought I would try and mimic what the Random class does. At the core of Random is the .Sample method. And right from go I am confused.
How do you create a Double greater than or equal to 0 and less than one from 8 random bytes? I have some code that appears to work but is slow, 6 seconds to produce 1,000,000 Doubles.
Code:
' Significand or mantissa 0-51
' Exponent 52 - 62
' Sign (0 = Positive, 1 = Negative) 63
' 8000000000000
Me._methodLock.WaitOne() 'for thread safety
Dim rv As Double = Double.NaN
Const MantMsk As Long = &HFFFFFFFFFFFFFL
Const ExpMsk As Long = &H7FF0000000000000L
Const Mask As Long = MantMsk Or ExpMsk 'negative numbers not possible with this mask
Dim L As Long = Long.MinValue
If Me.WaitForBytes(8) Then 'wait for there to be at least 8 bytes in the com buffer
Dim byteVal As New List(Of Byte)
Do While byteVal.Count < 8 'get eight bytes from the com buffer
Dim b As Byte
If Me.buf.TryDequeue(b) Then
byteVal.Add(b)
End If
Loop
' L is a long
L = Mask And BitConverter.ToInt64(byteVal.ToArray, 0)
Do
Dim ct As Integer = 0
rv = BitConverter.ToDouble(BitConverter.GetBytes(L), 0)
'1.#QNAN
If Double.IsInfinity(rv) OrElse
Double.IsNaN(rv) OrElse
Double.IsNegativeInfinity(rv) OrElse
Double.IsPositiveInfinity(rv) Then
L = L Xor Long.MinValue
ElseIf rv >= 0.0R AndAlso rv < 1.0R Then '
Exit Do 'success
End If
ct += 1
Dim foo As Long = L
Dim exp As Long = (foo And ExpMsk) >> 52
exp = (exp << 51) And ExpMsk
foo = (foo And MantMsk)
foo = foo Or exp
L = foo
Loop
Else
'todo
Stop
End If
Until I get the device I am filling the comport buffer with random bytes using the Random class.
-
Dec 1st, 2023, 04:32 PM
#2
Re: Random
For what its worth, here is the source code for Random: https://referencesource.microsoft.co...stem/random.cs
It is using the Linear Congruential Generator algorithm to initialize the seed. That's about as far down the rabbit hole I got.
Random is a topic similar to infinity for me. It's really cool but gets way over my head way too quickly.
-
Dec 1st, 2023, 10:08 PM
#3
Re: Random
Note that the Random class only produces pseudorandom numbers. They appear random to the casual observer but the sequence is predictable if you know the initial conditions. The RandomNumberGenerator class provides numbers that are sufficiently random for cryptographic use.
-
Dec 3rd, 2023, 03:28 AM
#4
Re: Random
Code:
x = BitConverter.Touint32(byteVal.ToArray, 0)
y = BitConverter.Touint32(byteVal.ToArray, 4)
rv = x / y
add code to care about the edge cases (y=0 and x=y if you do not want 1 as possible result)
edit: of course you need to exchange x and y if x > y so that y is always bigger or equal x. But i guess you get the point.
Last edited by digitalShaman; Dec 3rd, 2023 at 04:05 AM.
-
Dec 3rd, 2023, 08:08 PM
#5
Re: Random
 Originally Posted by digitalShaman
Code:
x = BitConverter.Touint32(byteVal.ToArray, 0)
y = BitConverter.Touint32(byteVal.ToArray, 4)
rv = x / y
add code to care about the edge cases (y=0 and x=y if you do not want 1 as possible result)
edit: of course you need to exchange x and y if x > y so that y is always bigger or equal x. But i guess you get the point.
Thought about something like this. I'll give it a try tomorrow. The device should be here Wednesday. Thanks!
-
Dec 5th, 2023, 01:09 PM
#6
Re: Random
This is where I am so far, still waiting on the actual device. I have ran some test for verification, see end.
Here is a question, could I use Int16 instead of Int32? Or should I use Int64?
Code:
''' <summary>
''' returns a double greater than or equal to 0 and less than 1
''' </summary>
''' <returns>Double</returns>
''' <remarks></remarks>
Private Function Sample() As Double
Dim rv As Double = Double.NaN
Dim int1 As Integer
Dim int2 As Integer
Dim byts() As Byte
int1 = 0
int2 = 0
'create two integers
Do While int1 = int2
byts = Me.GetBytes(4) 'get 4 bytes from com buffer
'use loop because .GetBytes might not return 4 bytes
For idx As Integer = 0 To byts.Length - 1
int1 = int1 << 8
int1 = int1 Or byts(idx)
Next
byts = Me.GetBytes(4) 'get bytes from com buffer
For idx As Integer = 0 To byts.Length - 1
int2 = int2 << 8
int2 = int2 Or byts(idx)
Next
'turn off sign
int1 = int1 And Integer.MaxValue
int2 = int2 And Integer.MaxValue
If int1 = int2 Then
int1 = int1 Xor Integer.MaxValue
End If
Loop
If int1 > 0 OrElse int2 > 0 Then
If int1 > int2 Then
rv = int2 / int1
Else
rv = int1 / int2
End If
Else
Stop 'todo ??????
End If
'does this happen?????
If Double.IsInfinity(rv) OrElse
Double.IsNaN(rv) OrElse
Double.IsNegativeInfinity(rv) OrElse
Double.IsPositiveInfinity(rv) Then
Stop 'todo
End If
Return rv
End Function
I ran 5,000,000 iterations of:
Heads / Tails and it was 50 / 50
Two dice and it matched the total distribution
Created integers and counted digits in the answer
-- ran the same thing against the System.Random and matched
As you can see there are some questions in the code that I will resolve when I get the device.
Is anyone interested about the device?
Results of significant digit count
System.Random
1 0.0000 %
2 0.0000 %
3 0.0000 %
4 0.0004 %
5 0.0045 %
6 0.0412 %
7 0.4186 %
8 4.1937 %
9 41.8918 %
10 53.4497 %
TRNG
1 0.0000 %
2 0.0000 %
3 0.0000 %
4 0.0004 %
5 0.0038 %
6 0.0428 %
7 0.4186 %
8 4.1972 %
9 41.8843 %
10 53.4530 %
Last edited by dbasnett; Dec 5th, 2023 at 01:13 PM.
-
Dec 7th, 2023, 06:35 AM
#7
Re: Random
A warning: I am not so sure anymore that this approach will generate evenly distributed numbers.
For example the result of Int.max-1 / int.max will only be possible with these exact two numbers while a result of 0.5 is generated by multiple number combinations such as 1/2, 2/4, etc.
-
Dec 7th, 2023, 01:06 PM
#8
Re: Random
 Originally Posted by digitalShaman
A warning: I am not so sure anymore that this approach will generate evenly distributed numbers.
For example the result of Int.max-1 / int.max will only be possible with these exact two numbers while a result of 0.5 is generated by multiple number combinations such as 1/2, 2/4, etc.
I was going to try to figure out the distribution but realized I didn't understand a lot of the code I looked at.
I did let the device run overnight turning on two pixels per second in a blank image.
Result:
-
Dec 9th, 2023, 01:47 PM
#9
Re: Random
 Originally Posted by digitalShaman
A warning: I am not so sure anymore that this approach will generate evenly distributed numbers.
For example the result of Int.max-1 / int.max will only be possible with these exact two numbers while a result of 0.5 is generated by multiple number combinations such as 1/2, 2/4, etc.
Haven't tested with the TRNG hardware but this works with Random.
Code:
Private prng As New Random
Private gtONE As ULong = 0UL
Private Function Sample() As Double
Dim rv As Double = 0.0#
'Bytes
'7 Mantissa 0-51
'2 Exponent 52-62 0 - 1022
Dim byts(8) As Byte '9 bytes
prng.NextBytes(byts) ' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<REPLACE with TRNG get
Dim exp As Long = 0L
If byts.Length > 1 Then
'create Exponent
exp = byts(0)
exp = exp << 8
exp = exp Or byts(1)
' keep 10 bits only
exp = exp And &H3FFL ''this mask &H1FFL stops >= 1.0 '
End If
If exp >= 1023 Then exp -= 1L
' If exp >= 1000 Then exp -= 23L ' but some exp >= 1000 are good
' e.g. 0.46678963503161 exp = 1021
exp = exp << 52 'position Exponent
Dim L As Long = 0L
For x As Integer = 2 To byts.Length - 1 'create Mantissa
L = L << 8
L = L Or byts(x)
Next
L = L And SignificandMSK '52 bits only
L = L Or exp 'add Exponent
rv = BitConverter.Int64BitsToDouble(L)
If rv >= 1.0# Then
rv = rv / Math.PI
Me.gtONE += 1UL
End If
If rv >= 1.0# Then
'todo
Stop
End If
Return rv
End Function
Last edited by dbasnett; Dec 10th, 2023 at 07:56 AM.
-
Dec 11th, 2023, 09:59 AM
#10
Re: Random
Great, just great. So I have been looking at the source of .Random. In it I find this.
Code:
public virtual int Next(int maxValue) {
if (maxValue<0) {
throw new ArgumentOutOfRangeException("maxValue", Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", "maxValue"));
}
Contract.EndContractBlock();
return (int)(Sample()*maxValue);
}
So my new .Sample apparently does a broader range.
8.7253577634378e-280
5.10351429655486e-168
7.66905992703698e-225
1.63228078929909e-137
4.81252807881766e-185
1.0806761131728e-158
6.00381557186564e-135
8.91585051435279e-183
6.63151599550507e-162
1.81935382013397e-138
2.28408466952934e-71
2.78949524958343e-283
2.43364313225461e-265
3.82096161246175e-165
4.3831210318899e-140
9.54907848369536e-123
4.76116207454203e-45
0.00277009731881507
6.20504061442252e-205
2.4889082471918e-20
8.67933824628034e-253
6.59549839909513e-49
8.6448449726707e-288
7.30206483116989e-111
3.26052204441488e-102
3.3667687899405e-128
1.70358091448857e-77
3.67136132927937e-269
3.41397071621818e-15
3.43220382872364e-155
2.58852200039163e-64
3.55377161269553e-68
3.16103698589824e-189
1.34132824028634e-196
4.7029016099803e-18
1.3649258957631e-292
8.71277705385738e-183
5.49958265719597e-29
4.36150273910638e-175
7.54537044298667e-15
6.01228626236831e-65
6.82407168351128e-05
2.00518986766811e-122
2.00214876288474e-104
6.97052809694117e-110
1.07402982506738e-62
1.75113941553553e-190
8.01532381965969e-278
5.87034189846368e-30
4.39118219624152e-193
1.12863560347159e-72
4.07807280569997e-183
1.33797727986362e-152
8.77861478648681e-271
6.52053556928832e-197
1.17493728755003e-116
6.11487766561578e-74
1.12273389231186e-176
3.58183377297382e-181
2.02060585288374e-236
3.29833187060158e-233
4.51661450924151e-149
3.40411805343502e-15
1.31057074649206e-126
Too broad to do this,
Code:
Dim rv As Double = Me.Sample() * maxValue
rv = CInt(Math.Truncate(smpl))
Return rv
Damn, damn, ....
-
Dec 14th, 2023, 11:13 AM
#11
Re: Random
I have resolved this with code based on System.Random. Left the original as a conditional.
Code:
Const MBIG As Double = 1.0# / Integer.MaxValue
Private Function ISample() As Double
Dim rv As Double = 0
#Const Methd = "1" ' "2"
Dim I1 As Integer = Me.Next 'get random integer between 0 and Integer.MaxValue
#If Methd = "1" Then
rv = I1 * MBIG
#ElseIf Methd = "2" Then
Dim I2 As Integer = Me.Next
If I1 > I2 Then
rv = I2 / I1
ElseIf I2 > I1 Then
rv = I1 / I2
ElseIf I1 <> Integer.MaxValue Then
rv = I2 / (I1 + 1)
Else
rv = (I2 - 1) / I1
End If
#End If
Return rv
End Function
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|