Генерирование массива псевдослучайных чисел

В этом рецепте я расскажу как получить массив фиксированного размера, который заполнен псевдослучайным числами, при этом не будет использован стандартный подход с проходом по созданному массиву с помощью цикла или функциональные шаблоны из стандартной библиотеки. Таким образом, в этой статье я напомню вам про то, что в D есть кое-что интересное, хотя и не столь часто используемое.

Перейдем же к заполнению массива псевдослучайными числами…

Предположим, нам нужен массив фиксированного размера с количеством элементов равным 10, и от этого количества и будем отталкиваться, к тому же при необходимости, вы сможете адаптировать код рецепта под свои нужды.

Сам код выглядит так:

import std.random : uniform;
int[10] array;
// array[] = 0;
array[] += uniform(0, 1000);

Этот код сначала инициализирует массив фиксированного размера, создавая набор нулевых элементов массива (т.е массив из 10 элементов int.init). Принципиально важно, чтобы в момент создания массива, в него попали именно значения вида cast(T) 0, где T — это тип элементов массива. Дело в том, что не все типы инициализируются нулем, особенно если учесть то, что существуют типы с плавающей точкой (инициализируются значением <имя типа>.nan) или же пользовательские числовые типы (могут быть инициализированы практически любым значением).

Далее, вступает в дело, так называемая поэлементная операция над элементами массива, которая в D записывается в нотации среза и представляет собой очень удобное средство для манипуляции массивами с уже известными размерами без непосредственного использования циклов. Такого рода операции подразумевают, что обозначенное некой конструкцией D действие применяется к каждому элементу массива, что на практике означает развертку действия в цикл или в векторную форму (зависит от реализации компилятора). С помощью uniform мы генерируем псевдослучайное число в интервале от 0 до 1000 (тип int) и прибавляем его к текущему элементу массива, который равен нулю, добиваясь этим того, что полученное псевдослучайное значение замещает собой значение из массива, а благодаря указанию [], подобная операция замены распространяется на весь массив!

Теперь когда с рецептом мы закончили, расскажу совсем немного про поэлементные операции…

Поэлементные операции над элементами массива — мощное средство, которое позволяет вам использовать некоторые операции сразу на весь массив без явного указания его элементов. Все, что нужно для применения этого средства языка — это некоторый массив с уже известным количеством элементов, некоторое элементарное действие и указание среза после каждого элементарного действия (нужно указать [] или [m..n], как говорит Александреску).

Обращаю внимание на то, что под результат выражения память уже должна быть выделена, иначе компилятор откажется выполнять развертку операции на весь массив:

auto c = new double[4]; // Па­мять под мас­сив долж­на быть уже вы­де­ле­на
c[] = (a[] + b[]) / 2;  // Рас­счи­тать сред­нее ариф­ме­ти­че­ское a и b
assert(c == [ 2.0, 2.5, 3.0, 0.5 ]); // Проверяем

В поэлементных операциях могут участвовать следующие элементы языка:

  • элементарное значение, например, некоторое целочисленное значение;
  • срез элементов массива, как без указания границ среза так и с их указанием, например, [] или [0..$/3];
  • любое корректное выражение D  с использованием унарных операций и ~; бинарных операторов +,,*,/,%,^^,^,&,|,=,+=,-=,*=,/=,%=,^=,&= и |=.

В общем, советую прочитать про поэлементные операции в книге Андрея Александреску «Язык программирования D» в разделе 4.1.7.

(Честно, взял у Александреску описание (глава 4.1.7 книги «Язык программирования D»), но и сам кое-что проверил: выяснилось, что так можно даже массивы складывать без циклов и не только, а еще и использовать некоторые функции стандартной библиотеки. Это безусловно заслуживает отдельного исследования, за которое мы быть может и возьмемся).

aquaratixc

Программист-самоучка и программист-любитель

Добавить комментарий