-3

The code works well now. You want to participate in the 6 out of 49 games of chance with a single (simple) option and you want to know your chances of winning:

Category I (6 numbers) Category II (5 numbers) Category III (4 numbers) Write a console application that calculates your chances of winning the lottery. Generalize the solution to work for any combination of total balls, balls drawn, and category.

The application takes as input the total number of balls, the number of balls drawn, and the category and then prints out the winning odds with an accuracy of 10 decimal places if only one variant is played.

Example:

For entry data:

40
5
II

The console will display:

0.0002659542

Here is the formula:

kCj * (n-j)C(k-j) / nCk 

which should translate to this

k!/(j!*(k-j)!)  *  (n-j)!/((k-j)!*(n-k)!)  /  n!/(k!*(n-k)!)

Here is my code:

using System;

class Program
{
    static void Main()
    {
        decimal totalNumbers = Convert.ToDecimal(Console.ReadLine()); // total numbers
        decimal extractedNumber = Convert.ToDecimal(Console.ReadLine()); // extracted numbers
        string numbersCategory = Console.ReadLine(); // numbers that have to be extracted
        decimal temporaryExtractedNumber; // this will be used to set the category
        const decimal first = 1;
        const decimal second = 2;
        decimal a;
        decimal b;
        decimal c;
        decimal result;
        if (numbersCategory == "I")
        {
            temporaryExtractedNumber = extractedNumber;
        }

        if (numbersCategory == "II")
        {
            temporaryExtractedNumber = extractedNumber - first;
        }

        if (numbersCategory == "III")
        {
            temporaryExtractedNumber = extractedNumber - second;
        }

        a = NCK(totalNumbers, extractedNumber, temporaryExtractedNumber);
        b = NCK(totalNumbers, totalNumbers - extractedNumber, extractedNumber - temporaryExtractedNumber);
        c = NCK(totalNumbers, totalNumbers, extractedNumber);

        result = a * b / c; // this is the magic formula
        Console.WriteLine(result.ToString("F10"));
    }

    static decimal NCK(decimal totalNumbers, decimal extractedNumber, decimal temporaryExtractedNumber)
    {
        if (extractedNumber == temporaryExtractedNumber)
        {
            return 1;
        }

        if (extractedNumber - temporaryExtractedNumber == 0)
        {
            return 1;
        }

        if (temporaryExtractedNumber == 0)
        {
            return 1;
        }

        decimal temp1;
        if (extractedNumber < temporaryExtractedNumber)
        {
            temp1 = extractedNumber;
            extractedNumber = temporaryExtractedNumber;
            temporaryExtractedNumber = temp1;
        }

        decimal kj = extractedNumber - temporaryExtractedNumber;
        if (temporaryExtractedNumber < kj)
        {
            temp1 = temporaryExtractedNumber;
            temporaryExtractedNumber = kj;
            kj = temp1;
        }

        decimal result1 = 1;
        for (decimal i = temporaryExtractedNumber + 1; i <= extractedNumber; i++)
        {
            result1 *= i;
        }

        decimal result2 = 1;
        for (decimal i = 1; i <= kj; i++)
        {
            result2 *= i;
        }

        return result1 / result2;
    }
}
       
  • 8
    This is a good opportunity to [start using a debugger](https://stackoverflow.com/q/25385173/328193). When you step through the code in a debugger you can observe the behavior and the changing values of your variables line by line. When you do this, which exact line of code produces the error? What were the exact observed runtime values of the variables used on that line of code at the time? – David Dec 20 '21 at 18:25
  • 35! is too large a number for the decimal type. You can try using `double` instead. – Hans Kilian Dec 20 '21 at 18:39
  • 4
    The thing about factorials is that they blow up quickly. But, when dealing with combinatorics like this, you can often do the calculations in a reasonable way be getting rid of common factors. For example `6!` is `6x5x4x3x2x1` and `4!` is `4x3x2x1` but you don't need to calculate either of those to calculate `6! / 4!`, that is simply `6x5` (since `4x3x2x1` are common to both calculations) – Flydog57 Dec 20 '21 at 19:13
  • 1
    This might be slightly helpful: https://stackoverflow.com/a/70398503/1566221 – rici Dec 21 '21 at 07:02
  • @David I started to use debugger, so the debugger comes to line 29 where is the first time when function should return the value, but the it just ignore it and jumps to line 30 and then appears the same message error. – Laurențiu Cozma Dec 21 '21 at 07:12
  • @rici I modified the code with what you commented in that post, but something goes wrong. I am using debugger and, when the code goes into function, my "k" is 0 even if i gave it "5" valor when I read it from console. static decimal jCk_helper(decimal j, decimal k). – Laurențiu Cozma Dec 21 '21 at 08:18
  • 1
    I think your code is not blowing up where you think it is.. https://dotnetfiddle.net/rT2IIo – Caius Jard Dec 21 '21 at 08:32
  • 1
    `decimal c = jCk(k, n);` supplies `jCk(5, 40)` and gets 0 into c, then tries to use this 0 to perform a divide on the `decimal r = a*b/c;` line – Caius Jard Dec 21 '21 at 08:36
  • 2
    *but the it just ignore it and jumps to line 30* - well, we can't see your line numbers and ours might be different so you should always state explicitly what line of code, but check you aren't pressing F10.. F10 is "step over" which runs functions without stepping into them (c# will go into the function and do everything in it and come out, but you only see the "come out" part), F11 steps into them. Debugging is a mix of F10 and F11 - some things you do want to step into, some you dont. You can also put breakpoints INSIDE functions you do want to pause in, and not inside those you don't – Caius Jard Dec 21 '21 at 08:42
  • Can you verify it again please? I updated the post. – Laurențiu Cozma Dec 21 '21 at 13:18
  • I rolled back your last edit because it changed the question in a way that made my answer meaningless. Please don't do this. SO is not a dialogue, nor is it an interactive debugging service. It's a repository of questions *of general utility* and their answers. If a question was worth asking here, that means that other people may require the answer to the same or a similar question, and if that's the case then you should not deprive them. If you think your question is only of interest to you, so that you can change it at will, then you shouldn't ask it here in the first place. – rici Dec 22 '21 at 22:51
  • If you need to, ask another question. But try harder to debug your program yourself first, and include any information you managed to gather while debugging. – rici Dec 22 '21 at 22:54

1 Answers1

1

Your formula is incorrect.

The probability of guessing exactly j correct numbers from a draw of k numbers selected from n possibilities is:

In your formula, the nk in the second binomial coefficient has been replaced with nj, leading to overcounting. For clarity, numerator of the fraction is the number of subsets where j numbers are drawn from the k winning numbers and kj numbers are drawn from the nk not-winning numbers.

With that minor change, you'll get the expected probability computation.


I only feel a little bad using codecogs. Client-side rendering with MathJax would be a lot better, IMHO, but that's not going to happen. In case Codecogs vanishes or overloads, here's the PNG: PNG of Codecogs render

rici
  • 219,119
  • 25
  • 219
  • 314