none
Birthday Paradox Calculator

    Question

  • With the information I've found from the birthday paradox, I'm trying to make a calculator similar to this but I cannot seem to figure out how to get a real number. The factorial of 365! gives an overflow. But it's not just VB, even my TI-84 Plus Silver Edition calculator gives an overflow as the number is so high.

    • What data types can I use to get numbers as high as "365!"?
    • Is there anyway I can get an accurate answer for the birthday paradox calculator in VB.NET?
    'Option Strict On
    
    Public Class Form1
    
        Private Function BirthdayParadox(ByVal people As Integer) As String
            ' P(A) prime
            Dim birthday As Decimal
    
            birthday = CDec((Factorial(365) / (Factorial(365 - people) * Math.Pow(365, people))))
    
            Dim output As Decimal
            output = (1 - birthday)
    
            Return output.ToString()
    
        End Function
    
        Public Function Factorial(ByVal Number As Decimal) As Decimal
            If Number = 0 Then
                Return 1
            Else
                Return Number * Factorial(Number - 1)
            End If
        End Function
    
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            Label1.Text = BirthdayParadox(TextBox1.Text)
        End Sub
    End Class
    
    


    Thanks,

    - Jordan


    If you find an answer helpful, click the Helpful button. If you find an answer to your question, mark it as the answer.
    www.metasdevelopment.com Jordan St. Godard | Microsoft Community Contributor © 2011

    Helpful Links:


    Wednesday, November 09, 2011 8:28 PM

Answers

  • The link to the calculator link you posted show how they arrive at their conclusion:

    365/365 + 364/365 + 363/365 + 362/365 + ... + 336/365

    So you can use an iterative approach:

        Sub Main()
            Dim numberOfPeople As Integer = 30
            Dim total As Double = 0.0
     
            For x As Integer = 0 To numberOfPeople
                total += CDbl(365 - x) / 365.0
            Next
     
            Console.WriteLine("Odds are {0} percent"100.0 - total)
     
            Console.WriteLine("Press ENTER to exit...")
            Console.ReadLine()
        End Sub
    

    I'm not sure you will be able to divide big integers and get a double result.

    Chris

    Wednesday, November 09, 2011 9:22 PM
  • The code example given:

        Sub Main()
            Dim numberOfPeople As Integer = 30
            Dim total As Double = 0.0
     
            For x As Integer = 0 To numberOfPeople
                total += CDbl(365 - x) / 365.0
            Next
     
            Console.WriteLine("Odds are {0} percent", 100.0 - total)
     
            Console.WriteLine("Press ENTER to exit...")
            Console.ReadLine()
        End Sub
    
    

    If you change 30 to 23, you get 76.75%, when according to what I have read, 23 is the point at which it should be 50%

    If you change 30 to 366, you get -82%

     Try this

    Module Module1
        Function different_birthdays(ByVal n As Integer) As Double
            If n = 1 Then
                Return 1
            Else
                Return different_birthdays(n - 1) * (365.0 - (n - 1)) / 365.0
            End If
        End Function
        Sub Main()
            Dim numberOfPeople As Integer = 23
            Dim total As Double = different_birthdays(numberOfPeople)
            Console.WriteLine("Odds are {0} percent", (1 - total) * 100)
            Console.WriteLine("Press ENTER to exit...")
            Console.ReadLine()
        End Sub
    End Module
    

    Thursday, November 10, 2011 1:52 AM

All replies

  • Have you tried BigInteger?
    Serial Port      Random      Microsoft® Community Contributor 2011
    Wednesday, November 09, 2011 8:55 PM
  • No? Never heard of it until now. How do I use it?
    If you find an answer helpful, click the Helpful button. If you find an answer to your question, mark it as the answer.
    www.metasdevelopment.com Jordan St. Godard | Microsoft Community Contributor © 2011

    Helpful Links:

    Wednesday, November 09, 2011 8:55 PM
  • The link to the calculator link you posted show how they arrive at their conclusion:

    365/365 + 364/365 + 363/365 + 362/365 + ... + 336/365

    So you can use an iterative approach:

        Sub Main()
            Dim numberOfPeople As Integer = 30
            Dim total As Double = 0.0
     
            For x As Integer = 0 To numberOfPeople
                total += CDbl(365 - x) / 365.0
            Next
     
            Console.WriteLine("Odds are {0} percent"100.0 - total)
     
            Console.WriteLine("Press ENTER to exit...")
            Console.ReadLine()
        End Sub
    

    I'm not sure you will be able to divide big integers and get a double result.

    Chris

    Wednesday, November 09, 2011 9:22 PM
  • Jordan,

    Apart from the question of the data type you need to use, I would try to simplify the calculation. Inded, 365! is such a huge number, it will cause overflow in any situation.

    Rather, I'd like to convince you that :

    365! / (365 - people)!

    is probably a lesser number, that can be easier to compute:

    365! / (365 - people)!  = 365*364*363 .... ("people" times)

    So if "people" is  a fairly low number, your computation won't overflow !

     

    Wednesday, November 09, 2011 9:24 PM
  • Jordan,

    Even if I use a double I get an error, but then a stackoverflow. I think it is in your case just a complex of that, for me it seems more that your recursive loop is somehow to endless or complex.

    Public Class Form1
        Private Function BirthdayParadox(ByVal people As DoubleAs String
            ' P(A) prime
            Dim birthday = Factorial(365.0#) / Factorial(365.0# - people * Math.Pow(365.0#, people))
            Dim output = (1.0# - birthday)
            Return output.ToString()
        End Function
        Public Function Factorial(ByVal Number As DoubleAs Double
            If Number = 0 Then
                Return 1
            Else
                Return Number * Factorial(Number - 1.0#)
            End If
        End Function
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgsHandles Button1.Click
            Label1.Text = BirthdayParadox(30.0#)
        End Sub
    End Class
    


    Success
    Cor
    Wednesday, November 09, 2011 9:25 PM
  • Sygrien:

    People is the parameter; I can't say that people will be a low number.

    dbasnett:

    Figured out bigInt. Thanks for the suggestion!

    http://msdn.microsoft.com/en-us/library/system.numerics.aspx

    http://msdn.microsoft.com/en-us/library/system.numerics.biginteger.aspx

    Chris:

    I didn't think of doing it that way. Thanks!

    Thanks again,

    - Jordan


    If you find an answer helpful, click the Helpful button. If you find an answer to your question, mark it as the answer.
    www.metasdevelopment.com Jordan St. Godard | Microsoft® Community Contributor 2011

    Helpful Links:

    Wednesday, November 09, 2011 9:35 PM
  • The code example given:

        Sub Main()
            Dim numberOfPeople As Integer = 30
            Dim total As Double = 0.0
     
            For x As Integer = 0 To numberOfPeople
                total += CDbl(365 - x) / 365.0
            Next
     
            Console.WriteLine("Odds are {0} percent", 100.0 - total)
     
            Console.WriteLine("Press ENTER to exit...")
            Console.ReadLine()
        End Sub
    
    

    If you change 30 to 23, you get 76.75%, when according to what I have read, 23 is the point at which it should be 50%

    If you change 30 to 366, you get -82%

     Try this

    Module Module1
        Function different_birthdays(ByVal n As Integer) As Double
            If n = 1 Then
                Return 1
            Else
                Return different_birthdays(n - 1) * (365.0 - (n - 1)) / 365.0
            End If
        End Function
        Sub Main()
            Dim numberOfPeople As Integer = 23
            Dim total As Double = different_birthdays(numberOfPeople)
            Console.WriteLine("Odds are {0} percent", (1 - total) * 100)
            Console.WriteLine("Press ENTER to exit...")
            Console.ReadLine()
        End Sub
    End Module
    

    Thursday, November 10, 2011 1:52 AM
  • Thanks for the correction.  I re-visited my approach and noticed where the problem lie.  I was using addition (+=) instead of multiplication (*=), but I like your recursive approach better.

    And naturally, if there are more than 365 people, the odds are 100 percent that two would have the same birthday.  But I wonder, what should be the correct return value if there is only one person?  Should it be 100% ?  Or is it undefined?


    Thursday, November 10, 2011 2:35 PM
  • And naturally, if there are more than 365 people, the odds are 100 percent that two would have the same birthday.  But I wonder, what should be the correct return value if there is only one person?  Should it be 100% ?  Or is it undefined?

    If one person 0%. Tested it with http://jeff.aaron.ca/cgi-bin/birthday and the code from above.

    - Jordan


    If you find an answer helpful, click the helpful button. If you find an answer to your question, mark it as the answer.

    Jordan St. Godard | Microsoft® Community Contributor 2011
    Meta's Development

    Helpful Links:

    Thursday, November 10, 2011 2:47 PM
  • It's probably worth adding the else if people > 365 return 100 so that you don't get stack overflow errors if someone puts in 1500 or something.  (And so that you don't get more than 100% as a result.)
    Thursday, November 10, 2011 5:47 PM
  • Up to and including 11193 people, you get 100%

    11194 and on, overflow

     

    Thursday, November 10, 2011 5:57 PM