Poisson delay formula/function for VB? - vb.net

I have a requirement where in I need to sleep for a Poisson duration before sending the next packet. The current formula I can think of is
( e^(-lambda) X lambda^t ) / fact(t)
However, for time steps 280 and more the fact(t) would become obsolete due to overflow.
Can someone help me workaround this conventional way in VB .NET?

I think you are looking for the inter-arrival time. A random inter-arrival time can be generated using
t = (Math.log(1.0-Math.random())/-lambda
The formula you posted is the one that defines the probability that there are exactly t (in your case) arrivals within a specific time period.
See the Wikipedia article on generating Poisson distributions.

Even though the factorial value is getting extremely large (as you've observed), the λ k term is also getting somewhat large to compensate. For a way to represent the distribution that takes this into account, see the Wikipedia article on the Poisson distribution:
A VB implementation might look something like:
Module Module1
Sub Main()
Console.WriteLine(Poisson(4, 250))
Console.ReadKey()
End Sub
Function Poisson(ByVal lambda As Integer, ByVal k As Integer) As Double
Poisson = Math.Exp(k * Math.Log(lambda) - lambda - SumOverLn(1, k))
End Function
Function SumOverLn(ByVal start As Integer, ByVal endval As Integer) As Long
Dim i As Integer
SumOverLn = 0
For i = start To endval
SumOverLn = SumOverLn + Math.Log(i)
Next
End Function
End Module
It looks like after a while it is so close to 0 that it registers as such. You may be able to adjust the precision of the display to get more decimal places, but 0 might be a decent enough approximation for high values (the notion that you get from the probability theory seems to be that those values are indeed very close to zero anyway).

Related

VBA Division of integers

It seems improbable that this is not a duplicate of a question that already has an answer but I can't find that question or answer so here I go...
In VBA, in the immediate window, if I type:
?8/7
I get the result:
1.14285714285714 which if I then multiply by 7 gives me a number that is slightly LESS than 8, i.e. 7.99999999999998. My pocket calculator provides more decimal places, so it's better than VBA? Right? ;-)
However, if I add 0.000000000000003 to the RESULT 1.142... before I multiply I get 8 (which, by the way, is also incorrect); but my question is:
How can I control the precision of the answer with respect to the number of decimal places shown for ?8/7?
I have seen this answer relating to the accuracy of floating points but it is a different question, it explains the reasons for the inaccuracies whereas I am interested in getting a few extra digits.
To this end I have tried writing a function that returns a double but it does not return enough decimal places... for example I'd like to see: 1.142857142857142857. I also found references to a decimal data type but I think the article is for VB6 (instead of VBA) think I have exhausted the available data types in VBA... what am I missing?
Function test() As Double
Dim a As Double
Dim b As Double
Dim c As Double
a = 8
b = 7
c = a / b
test = c
End Function
Graphing and scientific calculators are not built for speed. They can afford to use software implementation of decimal floats for their calculations rather than IEEE doubles. So it is quite possible that your pocket calculator has greater precision than VBA, but at a cost. What they do is likely to be more than an order of magnitude slower.
VBA lacks a built-in arbitrary precision floating point library, but its decimal type supports higher precision than doubles. Unfortunately, it isn't a full-fledged data type but is rather a subtype of Variant. To create them, you need to use CDec():
Sub test()
Dim x As Variant
x = CDec(8) / 7
Debug.Print x
End Sub
This displays 1.1428571428571428571428571429
When using Decimal, you need to be aware of the fact that if you are not careful, they can pop back to e.g. a Double depending on how you use them:
Sub test2()
Dim x As Variant
x = CDec(x)
Debug.Print TypeName(x)
x = 8 / 7
Debug.Print x
Debug.Print TypeName(x)
End Sub
Output:
Decimal
1.14285714285714
Double

VBA Integer vs Long for counting tries on check if random number is equal to picked number at a range of 1 to 100

Last week I had to take a test in VBA. I had to code a little "game". These were the rules:
Pick a number between 1 and 100 (1 and 100 included)
Call function Randomize
Generate a random number between 1 and 100 (1 and 100 included) -> Int (100 * Rnd + 1)
Check if random number = chosen number.
5.1 If true, add +1 to counter, print counter, game is finished
5.2 If false, add+1 to counter, go back to Step 3.
I hope you get the aim of the "game".
I initialized the counter as an Integer (16 bit). My teacher told me that it is possible, that the counter might overflow. He recommends using a Long (32 bit) so that the chance to overflow is smaller.
I told him that it is nearly impossible to reach 32000 tries on the counter, because the chance that the picked number is equal to the generated number is 1:100.
He replied: But it's still possible.
My question:
Is it possible that the counter might overflow if the datatype is Integer? If yes, what's the chance? If no, how can I proof it?
Why is this question on stackoverflow and not on statistics?
It's simple. Because you guys know the Rnd-function and VBA behind the scenes, the guys on statistics don't.
Something like this I used in the past for file sampling, bringing the question is a Byte sufficient (1-255)?
Public dicGeneratedAlready As Scripting.Dictionary
Public Function GENERATE_RANDOM(intFromNumber As Integer) As Integer
Randomize
If dicGeneratedAlready Is Nothing Then Set dicGeneratedAlready = New Scripting.Dictionary
GenerateRand:
GENERATE_RANDOM = Int((Rnd * intFromNumber) + 1)
If dicGeneratedAlready.Exists(CStr(GENERATE_RANDOM)) Then
GoTo GenerateRand
Else
dicGeneratedAlready.Add CStr(GENERATE_RANDOM), CStr(GENERATE_RANDOM)
End If
End Function
From your description above there seems to be nothing stopping the code from trying numbers it has already tried before, so theoretically a long doesn't help, that could overflow as well, i.e. this could go on to infinity

True Random Number Generating

So basically, I have this function that is supposed to generate two random integers between a high and a low number, to make a point on the form. I know that Random can handle this, but Random has consistency, whereas I need the numbers to be completely random on the form.
For example, most of my generated points appear in a diagonal line. This is what I want to avoid. It should go all over the form between the high and low numbers.
Here is my current function:
Function GetNewLocation() As Point
Randomize()
Dim int1 As Integer = RandomNumber(6, 345)
Randomize()
Dim int2 As Integer = RandomNumber(35, 286)
Return New Point(int1, int2)
End Function
Function RandomNumber(ByVal low As Integer, ByVal high As Integer) As Integer
Randomize()
Return New Random().Next(low, high)
End Function
How can I get true random number generation where the point is not on a diagonal line?
Each time you create a new instance of Random you are resetting the random number generator. Since the default constructor uses Environment.TickCount as the seed you are often returning precisely the same sequence of pseudo-random numbers. The system does not update TickCount that often. This is why it seems to you that you are getting non-random numbers.
Try changing your code like this:
Private _rnd As New Random()
Function RandomNumber(ByVal low As Integer, ByVal high As Integer) As Integer
Return _rnd.Next(low, high)
End Function
There is no true randomness in computer systems. There are many algorithm to generate "random" numbers but they are always based on a seed, like the time, process id, a mix of both, or on more advanced cases where randomness is taken seriously, on sounds being detected in a microphone, data from atmospheric sensors or cosmic microwave background, but it will always derivate from some existing source of information.
Thats also not the best slution.
I prefer my own code:
Dim old As Integer = 6572
Public Function Rand(ByVal min As Integer, ByVal max As Integer) As Integer
Dim random As New Random(old + Date.Now.Millisecond)
old = random.Next(min, max + CInt(IIf(Date.Now.Millisecond Mod 2 = 0, 1, 0)))
Return old
End Function
Thats a little bit better
I literally just came up with this solution. Maybe it will help =)
I went from:
Dim rand As Random = New Random(DateTime.Now.Millisecond)
To
Dim rand As Random = New Random(DateTime.Now.Millisecond * DateTime.Now.Second * DateTime.Now.Minute * DateTime.Now.Hour)
And it seems to have worked really well.
You can see the difference in the side by side.
in java(assuming the limit is (limit-1)):
random = System.currentTimeMillis()%limit;
You get the idea :)

Getting Duplicate Random Numbers

I'm doing basic random number generation using this Shared Function:
Public Shared Function RandomNumber(ByVal MaxNumber As Integer, Optional ByVal MinNumber As Integer = 0) As Integer
'initialize random number generator
Dim r As New Random(Date.Now.Ticks And &HFFFF)
If MinNumber > MaxNumber Then
Dim t As Integer = MinNumber
MinNumber = MaxNumber
MaxNumber = t
End If
Return r.Next(MinNumber, MaxNumber)
End Function
Called like this: dim x as integer = Random(2100000000)
Very simple, and the seed value comes straight from a MS example.
HERE'S THE PROBLEM: I'm getting duplicate numbers on occasion, but always created at times that are usually at least 5 or 10 minutes apart. I can see if I was calling the function multiple times per second or millisecond, because that'd kind of "breaks" the seed. But these are showing up at extended time spans. What else could be causing this?
Duplicate seed issue?
It might be better defining r as static so that it is initialised once when first invoked. Refer to this answer Random integer in VB.NET
The Random constructor takes an Integer as its parameter which is 32-bits. As spencer7593 said, with only 16 bits, you're repeating the sequence every 6.5ms. Try:
Dim r As New Random(Date.Now.Ticks And &HFFFFFFFF)
However, this will do the same thing:
Dim r As New Random()
Better yet, don't create a new Random object each time:
Private Static r As New Random()
Public Shared Function RandomNumber(MaxNumber As Integer, Optional MinNumber As Integer = 0) As Integer
...
Return r.Next(MinNumber, MaxNumber)
End Function
Q: What else could be causing this?
A: It could be happening purely by random. Random numbers are just that: random. At any point in time, whether its seconds or hours away from another point in time, its just as likely for a number to appear as any other number. There is no guarantee that a number won't be repeated.
On the other hand, it looks like your seed value is only on the order of 16 bits. And that's like a total of 65,536 possibilities. There's 10,000 ticks in a millisecond, so ever 6.5 milliseconds you have the possibility of reusing the same seed.
It's not at all clear whether the VB Random is using some other kind of entropy beyond that seed or not. (But gathering entropy for inclusion would slow down the initialization, so it may not be, as a performance consideration.)
According the docs, creating two Random objects using the same seed value results in Random objects that create duplicate sequences of unique numbers.
http://msdn.microsoft.com/en-us/library/ctssatww.aspx
I think that answers the question why it is happening.
I guess the next question is why do you need to instantiate a new Random object? If you need multiple objects, then instantiating several of them, but making sure you are using a different seed value for each one would be one approach.
But before you go there, I recommend you consider using just one Random. Calls to get random numbers can be serviced from an existing Random, rather than creating a new one every time you need a random number.
Try it another way:
Public Function RandomNumber2(ByVal MaxNumber As Integer, Optional ByVal MinNumber As Integer = 0) As Integer
' Initialize the random-number generator.
Randomize()
' Generate random value between MaxNumber and MinNumber.
Return CInt(Int((MaxNumber * Rnd()) + MinNumber))
End Function
See Randomize Function (Visual Basic) for more details. Hope this helps.

Using Randomize() before Rnd() in VB.NET

I have previously been told that I should always use Randomize() before I use Rnd() in a VB.NET application. Yet, it always seems to work fine without it. What does adding Randomize() do for me in this case?
It doesn't appear to affect my application in the least.
In Visual Basic, Rnd() uses a mathematical operation to produce the next "random" number. Because the actual operation is known, given a specific value, you can predict the next value. However, given an arbitray start value the numbers have good distribution - these are "pseudo-random" numbers.
To keep Rnd() from startng at a predictable number (and hence giving the same sequence of "random" numbers every time), Randomize() should be called to use the machine clock to set the initial value (called a seed).
(In the .NET world, I'd use System.Random instead if you can.)
Randomize() initializes the first seed of Rnd(). If you won't use it - VB.NET will use the default seed number.
Randomize will set the seed to something time related, like the system uptime or the system date. So the function Rand() will show different values every time the app is executed. However, I highly recommend you to use the System.Random class instead of VisualBasic Rand(). No need to call any randomize() function
Here are some example code, this will generate six random integers from the lower to upper bounds:
Dim randObj As New Random( seed )
Dim j As Integer
For j = 0 To 5
Console.Write( "{0,11} ", randObj.Next( lower, upper ) )
Next j
Console.WriteLine( )