You need to create M evenly distributed random numbers from the range [0, N), but there is one caveat here.
It should be noted that your statement of the problem is ambiguous. What is meant by a uniformly distributed choice? It is one thing to say that each index should be chosen with equal probability (of course, M / N). Another thing is that each combination with two indices should be chosen with equal probability. These two do not match. Which one did you mean?
If M is much smaller than N, the classic algorithm for choosing M numbers from the range [0, N) is Bob Floyd's algorithm, which can be found in Bentley’s book Pils Programming. It looks like this (sketch)
for (int j = N - M; i < N; ++j) { int rand = random(0, j); // generate a random integer in range [0, j] if (`rand` has not been generated before) output rand; else output j; }
To implement a check that rand already generated or not for a relatively high M, some set implementation is required, but in your case, M = 2 is simple and simple.
Note that this algorithm distributes the sets of numbers M uniformly. In addition, this algorithm requires exactly M iterations (attempts) to generate M random numbers, i.e. It does not follow that the erroneous trial-and-error approach is often used in various ad-hoc algorithms designed to solve the same problem.
Applying the above to your specific situation, the correct algorithm will look like this
first = random(0, N - 2); second = random(0, N - 1); if (second == first) second = N - 1;
(I leave the internal details of random(a, b) as the implementation detail).
It cannot be immediately seen why this works correctly and creates a truly uniform distribution, but it really :)