Редактировать: Как отмечает @Tonci, сумма 3 равномерных случайных величин не является равномерной случайной величиной. Фактически для a,b,c,d
вероятность быть около 0 примерно в 1,5 раза больше вероятности около 1 (или около -1). Поэтому ответ ниже является лишь приблизительным. Я оставляю это здесь, потому что, возможно, это может дать кому-то правильное вдохновение.
Октаэдр определяется 8 разграничивающими плоскостямиУравнения этих плоскостей являются обобщением abs(x) + abs(y) + abs(z) <= 1
, где abs
каждый раз может быть либо положительным, либо отрицательным. Итак:
x + y + z <= 1; x + y - z <= 1; x - y + z <= 1; x - y - z <= 1;
-x + y + z <= 1; -x + y - z <= 1; -x - y + z <= 1; -x - y - z <= 1
Объединение уравнений противоположной плоскости:
-1 <= x + y + z <= 1; -1 <= x + y - z <= 1; -1 <= x - y + z <= 1; -1 <= x - y - z <= 1
Теперь выберите значения для каждого из этих выражений:
x + y + z = a; x - y + z = b; x - y - z = c; x + y - z = d
Или для каждого случайного x,у, z внутри октаэдра у нас есть 4 значения:
-1 <= a <= 1; -1 <= b <= 1; -1 <= c <= 1; -1 <= d <= 1
Работая в обратном порядке, если у нас есть значения для a, b, c, d, мы можем найти соответствующие x, y, z. Эти уравнения линейно зависимы, случайным образом выбирая 3 из a, b, c, d, мы можем вычислить четвертое, а также x, y, z.
Поэтому выбираем случайные числа a, b, c в трех направлениях. Все в диапазоне от -1 до 1:
x + y + z = a
x - y + z = b
x - y - z = c
Решение для x, y, z: x: a/2 + c/2, y: a/2 - b/2, z: b/2 - c/2
.
В коде:
val a: Double = 2*nextDouble()-1 // range -1..1
val b: Double = 2*nextDouble()-1 // range -1..1
val c: Double = 2*nextDouble()-1 // range -1..1
val x: Double = (a+c) / 2
val y: Double = (a-b) / 2
val z: Double = (b-c) / 2
или с меньшим количеством операций:
val a: Double = nextDouble() // range 0..1
val b: Double = nextDouble() // range 0..1
val c: Double = nextDouble() // range 0..1
val x: Double = a+c-1
val y: Double = a-b
val z: Double = b-c