2

I am doing the stress testing for the following problem of my function myFunc().

There is a stone bridge connecting two cities. The first stone starting from one city is having 1 inscribed on it, and the last stone is on another city side. Each subsequent stone has two consecutive numbers on it except the last stone which may have one or two numbers inscribed on it depending on the value of N. Stones may be aligned as 1, (2, 3), (4, 5), (6, 7)... N.

You are given a number N representing the last number on the last stone; and a number X. The task is to find the minimum number of jumps you need from either the first city side or the second city side to reach the stone that has X inscribed on it. Note: Jumping on the first stone will be counted as 0 jumps.

Example: Input: 2 10 3 5 1

Output: 1 0

Explanation: Testcase 1: Stone alignment for N = 10 is as follows: 1, (2, 3), (4, 5), (6, 7), (8, 9), 10 To jump on X = 3, you only need one jump (since first stone jump will not be counted) from First city side, and 4 jumps from the second side. So the minimum of 1 and 4 is 1.

Testcase 2: Stone alignment for N = 5 is as follows: 1, (2, 3), (4, 5) To jump on X = 1, you only need zero jumps (since first stone jump will not be counted) from First city side, and 2 jumps from the second city side. So the minimum of 0 and 2 is 0.

#include <iostream>
#include <algorithm>
#include <ctime>
using namespace std;

int myFunc(int n, int p) {
    return p / 2;
}

int findJumps(int n, int p){
    return min(X /2, (N / 2) - (X / 2));
}
int main() {
    int n, x;
    srand(time(0));
    while(true) {

        n = rand() % 40 + 1; // I want n to be always greater than x
        x = rand() % 40 + 1;
        if(myFunc(n, x) != findJumps(n, x)) {
            cout << n << " " << x;
            break;
        }

        else cout << n << " " << x;
        cout << endl;
    }
    return 0;
}

What I want my code is to generate N always greater than X in the infinite loop scope. How can I enforce this condition?

Arun Suryan
  • 1,615
  • 1
  • 9
  • 27

2 Answers2

5

Let me start by advising that you avoid using rand (at all) and % to limit its output to a particular range. If you really insist on doing so anyway, skip ahead to the C Library section below for a way that's at least semi-reasonable.

Modern Library

C++ 11 introduced a new set of classes to generate random numbers, and reduce random numbers to a specified range. Using them is kind of a mixed bag though--some parts (like seeding) are a bit more difficult, while other parts (like reducing to a range) are rather simpler--at least if you care about doing the job well.

I'd also note that if 0 < x < n, then the lower limit on n must be 2, not 1.

Using the C++ 11 random number generation classes, you might do something on this general order:

std::mt19937 gen{ std::random_device()() };

// ...

int n = std::uniform_int_distribution<int>(2, 40)(gen);
int x = std::uniform_int_distribution<int>(1, n)(gen);

If you really care about the quality of the random numbers, you might want to go quite a bit further though--right now, this uses only a single return value from std::random_device to seed the generator, but the mt19937 generator actually has a much larger state than that, so a larger seed would be better. If you want to get into this, you might want to look at std::seed_seq as a starting point.

C Library

If you're going to use rand() and % to reduce your numbers to the right range, I guess I'd start by writing a small function to generate a random number within a specified range1:

int rand_range(int lower, int upper) { 
    int range = upper - lower;

    return rand() % range + lower;
}

Then I'd use that to generate the numbers:

n = rand_range(2, 40);
x = rand_range(1, n);

[As above, the lower limit on n must be 2.]

Another possibility would be to generate the two numbers, then if they're in the wrong order, swap them. That still leaves the possibility that they're equal though, and eliminating that possibility would be more work--thus the preceding advice to just assure that when you generate x, it always starts out strictly less than n.


1. Note that unless the range of the rand() happens to be a multiple of 40 (which is unlikely to be the case), using % like this generates biased results. If you want to do better, you might look at the https://stackoverflow.com/a/2999130/179910 for a somewhat improved method--but the standard distribution shown in the Modern Library section is really the right way to go here.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
2

As pointed by Mark Ransom, one simple and good solution that I came across is that simple check if(x > n) swap(n, x).

So, the driver code may look like:

int main() {
int n, x;
srand(time(0));
while(true) {

    n = rand() % 40 + 1; // I want n to be always greater than x
    x = rand() % 40 + 1;
    if(x > n) swap(n, x);
    if(myFunc(n, x) != findJumps(n, x)) {
        cout << n << " " << x;
        break;
    }

    else cout << n << " " << x;
    cout << endl;
}
return 0;

}

Arun Suryan
  • 1,615
  • 1
  • 9
  • 27
  • Strictly speaking, this doesn't meet the stated requirement that `n` is always greater than `x`. You're not considering the possibility that the two values could be the same. If you really need `n` strictly greater than `x`, you should test for the case where they're equal, and choose again if they are. – Caleb Mar 18 '20 at 18:52
  • Well, it solves the given problem. Is there any other method from which we can do this? – Pikachu Mar 19 '20 at 08:31