C/C++. The definition of the range for random numbers. Division with remainder and without

В программировании есть такие арифметические операции – деление с остатком a%b, обозначим результат через q  и целочисленное деление без остатка a/b, результат обозначим через r. Тогда в общем виде делимое число можно представить следующим образом, где a – делимое число, b - делитель:

                                                               a=b*r + q

В C++ есть генератор случайных целых чисел – int rand() – диапазон выдаваемых значений ограничен размером внутренней константы RAND_MAX - от 0 до 32767. Но на практике иногда приходится работать с более узкими диапазонами. Как же можно сузить диапазон в данном случае? Для этого прибегают к такому ухищрению:

                                                             rand()%x + y

В этом случае мы будем получать случайные числа из диапазона между y и x, то бишь

                                                        y ≤ rand()%x + y ≤ x

Корректно ли использовать данный подход? Для поиска ответа снова воспользуемся вышеприведенным выражением:

                                                                  a = b*r + q

С точки зрения программирования это выражение можно представить и так:

                                                            a = b*(a/b) + (a%b)

Мы знаем, что в случае, когда a кратно b, то второе слагаемое равно нулю:


То есть в точках 2n и 2n+1 q обращается в ноль. Рассмотрим этот диапазон, для этого предположим, что a/b лежит между 2n и 2n+1, запишем это утверждение следующим образом:

                            (a/b) = 2n + ε, где ε - величина смещения в диапазоне от 2n до 2n+1

Подставим данное уравнение в общее уравнение:

                                                          a = b(2n + ε) + q = 2nb + bε + q,
                                                                      q(ε) = a - 2nb - bε


Так как 0 ≤ ε ≤ 1, то q(1) ≤ q ≤ q(0), здесь стоит оговориться – возможно, что покажется неочевидным второе неравенство, но если посмотреть внимательно на полученное уравнение:

                                                                      q(ε) = a - 2nb - bε,

то можно видеть, что чем больше ε, тем меньше q(ε)   и наоборот, чем меньше ε, тем больше q(ε). Отсюда имеем математическое неравенство q(1) ≤ q ≤ q(0), раскроем его и решим:

                                                                     a - 2nb - b ≤ q ≤ a - 2nb,

                                                                                   -b ≤ q ≤ 0

Перемножим обе части неравенства на -1:

                                                                                    0 ≤ q ≤ b

Перепишем это неравенство с точки зрения программирования:

                                                                                 0 ≤ (a%b) ≤ b

Таким образом, мы доказали (подтвердили) правильность подхода при сужении диапазона выходных случайных чисел для тех или иных практических задач с помощью вот такого выражения:

                                                                                  rand()%x + y  

Всем отличного утра, дня или ночи :)