Генерация случайных дробных чисел

146
28 апреля 2018, 15:43

Есть вот такая задача: Сгенерировать массив чисел, сумма которых составит 1. Кол-во чисел вводится с клавиатуры. Решение может быть любое главное получить итоговую сумму 1 (Не желательно большое кол-во нулей)

Answer 1

Генерируем N любых неотрицательных чисел.
Вычисляем их сумму.
Делим каждое на эту сумму.

Пример реализации:

int count = 10;
Random random = new Random();
int[] integers = new int[count];
long sum = 0;
for (int i = 0; i < count; ++i)
{
    integers[i] = random.Next();
    sum += integers[i];
}
double[] doubles = new double[count];
for (int i = 0; i < count; ++i)
    doubles[i] = (double)integers[i] / sum;
Console.WriteLine(string.Join("\n", doubles));
Console.WriteLine(doubles.Sum());

random.Next() возвращает неотрицательное случайное целое число.
Для накопления суммы берем long-переменную во избежание переполнений.

Answer 2

rnd - Random

 static double[] Generate(int count)
 { 
    var result = new double[count];
    var max = 1.0;
    for (int i = 0; i < count - 1; i++)
    {
       result[i] = rnd.NextDouble() * max;
       max -= result[i];
    }
    result[count-1] = max;
    return result;
 }

Дополнительно массив можно перемешать если критично то, что при такой генерации в среднем следующее значение становится меньше предыдущего. Пример простого перемешивания:

result.OrderBy(x => rnd.Next()).ToArray();

Answer 3

Ну, раз ограничений никаких нет, то самое примитивное решение: массив в котором первый элемент равен 1, а остальные — 0.

int n = 5;
var arr = new decimal[n];
arr[0] = 1;

ОБНОВЛЕНИЕ: Добавлено уточнение, что много нулей нежелательно. Из-за этого решение не подходит.

Вариант №2: Заполняем массив значениями 1/n:

int n = 6;
var value = 1.0m/n;
var arr = Enumerable.Repeat(value, n).ToArray();

Тут возникает проблема: из-за ошибок округления при делении, сумма может не сойтись. Для того, чтобы сумма сошлась компенсируем первый элемент:

arr[0] = 1-(value*(n-1));
Answer 4

Выбранный (на данный момент) вариант с делением на сумму заранее сгенерированных чисел не дает равномерного распределения результата из-за того, что сумма равномерно распределенных величин сама не является равномерно распределенной. А равномерность распределения результата в таких задачах обычно подразумевается.

Более подходящим с точки зрения распределения решением будет следующее: сгенерировать N-1 неубывающих равномерно распределенных случайных чисел в диапазоне [0, 1]

r1, r2, ..., rN-1

затем положить r0 = 0 и rN = 1 и в качестве искомых чисел взять попарные разности в соседях

r1 - r0, r2 - r1, r3 - r3, ..., rN - rN-1

На C++

#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
  unsigned N = 10;
  std::vector<unsigned> r(N + 1);
  r.front() = 0;
  std::generate(r.begin() + 1, r.end() - 1, std::rand);
  std::sort(r.begin() + 1, r.end() - 1);
  r.back() = RAND_MAX;
  for (unsigned i = 1; i <= N; ++i)
    std::cout << double(r[i] - r[i - 1]) / RAND_MAX << " ";
  std::cout << std::endl;
}
Answer 5

Одна из идей - создавать большие целые числа, а затем делить их, к примеру, на 1000. Так у Вас сформируется массив дробных чисел =) Действия выполняемых, пока сумма всех элементов не станет равной 1. Каждое сформированное число нужно проверить: подходит ли оно условию (должно быть меньше разности 1 и сумма остальных элементов массива).

READ ALSO
Derived Control: Implement CreateHandle

Derived Control: Implement CreateHandle

Как правильно реализовать производный от SystemWindows

155
Получение данных из Mysql C#

Получение данных из Mysql C#

Необходимо получить balance по userid

124
c# system.IO.Directory.GetDirectories нужен метод для сортировке по Дате

c# system.IO.Directory.GetDirectories нужен метод для сортировке по Дате

я начинающий в c#Написана довольно большая консольная программа в ней множество раз получается массив методом system

123