0

Note that the question title is:

Random math question generation algorithm not working

because I can't enter "question" in question title...


So I am writing an android app that helps little kids learn maths by giving math questions to them. They can change the number of digits and the type of operation as they like. I am now confused with this algorithm that I wrote to generate random questions. It is generating the same question every time if with the same question options. For question options

number of digits: 1
operation: +

It is always 10 + 10.

Question options

number of digits: 2
operation: +

It is always 11 + 11.

Question options

number of digits: 3
operation: +

It is always 8 + 8.

Question options

number of digits: 2
operation: +

It is always 11 + 11.

Although the other operation types (-, +/-, *) are a bit more random, one of its operands is always the same. 1 digit is 10, 2 digits is 11, 3 digits is 8.

Now here is my algorithm:

public void generateAQuestion () {
    switch (options.getOperationType ()) {
        case ADDITION:
            current = generateAddition ();
            break;
        case SUBTRACTION:
            current = generateSubtraction ();
            break;
        case ADD_AND_SUB:
            current = generateAddAndSub ();
            break;
        case MULTIPLICATION:
            current = generateMultiplication ();;
            break;
    }
}

private int generateNumberWithDigitCount () {
    int minValue = 10 ^ (options.getDigitCount () - 1);
    int maxValue = 10 ^ options.getDigitCount () - 1;
    Random r = new Random ();
    return r.nextInt (maxValue - minValue + 1) + minValue;
}

private Question generateAddition () {
    int operand1, operand2;
    operand1 = generateNumberWithDigitCount ();
    operand2 = generateNumberWithDigitCount ();
    return new Question (operand1, operand2);
}

private Question generateSubtraction () {
    int operand1 = generateNumberWithDigitCount ();
    Random r = new Random ();
    int operand2 = -(r.nextInt (operand1));
    return new Question (operand1, operand2);
}

private Question generateAddAndSub () {
    Question firstPart;
    if (Math.random () > 0.5) {
        firstPart = generateAddition ();
    } else {
        firstPart = generateSubtraction ();
    }
    int[] operands = new int[3];
    operands[0] = firstPart.getOperands ()[0];
    operands[1] = firstPart.getOperands ()[1];

    if (Math.random () > 0.5) {
        Random r = new Random ();
        operands[2] = -(r.nextInt (firstPart.getAnswer ()));
    } else {
        operands[2] = generateNumberWithDigitCount ();
    }

    return new Question (operands);
}

private MultiplicationQuestion generateMultiplication () {
    return new MultiplicationQuestion (generateNumberWithDigitCount (), generateNumberWithDigitCount ());
}

private int[] generateAnswers (int correctAnswer) {
    int[] answers = new int[4];
    Random r = new Random ();
    int correctAnswerIndex = r.nextInt (4);
    answers[correctAnswerIndex] = correctAnswer;
    for (int i = 0 ; i < answers.length ; i++) {
        if (i == correctAnswerIndex) {
            continue;
        }

        if (Math.random () > 0.5) {
            answers[i] = correctAnswer + (i + 1);
        } else {
            int candidate = correctAnswer - (i + 1);
            if (candidate < 0) {
                candidate = correctAnswer + i + 5;
            }
            answers[i] = candidate;
        }
    }
    return answers;
}

Notes: options is the question options, its methods are self explanatory, you can get it.Don't care about the Question and MultiplicationQuestion's constructors, they are irrelevant.

And I don't know what I did wrong, everything makes sense to me. What did I do wrong?

Sweeper
  • 213,210
  • 22
  • 193
  • 313

4 Answers4

4

what is wrong here is where you use 10 ^ options.get... that isnt the same as power, you can in turn use Math.pow(10, options.get...)

The problem you have is that the ^ operator does not act as a exponent mod in this case :)

edited code

int minValue = (int)(Math.pow(10, (options.getDigitCount () - 1));
int maxValue = (int)(Math.pow(10, options.getDigitCount ())-1;

I completely understand why you got this wrong, as it is taught in many math classes that the ^ symbol means power

Kore
  • 436
  • 2
  • 14
3

Random r = new Random (); re-initialises the generator.

Do that once, not each time you need a number. Otherwise you ruin the statistical properties of the generator.

Then separate the minValue and maxValue values to have different values, currently they are equal, and probably meaningless due to the misuse of the XOR operator ^.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • `new Random()` should use a seed that is unlikely to have been used in past instantiations, according to the doc... – dotvav Aug 25 '15 at 09:26
  • 1
    It still completely ruins the generator's statistical properties. – Bathsheba Aug 25 '15 at 09:26
  • I agree. I was going to point it out in the comments, but I feel like it is not by itself an answer to the question. The point about min and max is more likely to be the root cause. – dotvav Aug 25 '15 at 09:27
  • I cite both. But I think misuse of random generators is *far* worse. (And @TDG spotted that before I did ;-)) – Bathsheba Aug 25 '15 at 09:29
  • @Bathsheba, "You ruin the statistical properties". Why? The chances of `nextInt(2)` returning 1 will always be 50%. – Sander Aug 25 '15 at 09:32
  • Rubbish. I've studied this extensively and I am correct. Google for more details. – Bathsheba Aug 25 '15 at 09:33
3

^ is the XOR operator in Java. Given that, your expressions for max and min value do not make sense.

Henry
  • 42,982
  • 7
  • 68
  • 84
1

The operator ^ is not for taking the power but for exclusive bitwise or.

Have a field:

private Random rand = new Random();

private int generateNumberWithDigitCount () {
    int pow10max = 1;
    for (int digits = options.getDigitCount(); digits > 0; --digits) {
        pow10max *= 10;
    }
    int pow10min = pow10max / 10;
    return pow10min - rand.nextInt(pow10max - pow10min);
}
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138