Вы можете легко оценить, какую ошибку (планки погрешностей) вы должны получить, в этом вся прелесть Монте-Карло. Для этого вам нужно вычислить второй импульс и оценить дисперсию и стандартное отклонение. Хорошо, что собранное значение будет таким же, как и среднее, потому что вы просто сложили 1 после 1 после 1.
Затем вы можете получить оценку сигмы моделирования и планки погрешностей для желаемого значения. Извините, я недостаточно знаю Javascript, поэтому код здесь на C#:
using System;
namespace Pi
{
class Program
{
static void Main(string[] args)
{
ulong N = 1_000_000_000UL; // number of samples
var rng = new Random(312345); // RNG
ulong v = 0UL; // collecting mean values here
ulong v2 = 0UL; // collecting squares, should be the same as mean
for (ulong k = 0; k != N; ++k) {
double x = rng.NextDouble();
double y = rng.NextDouble();
var r = (x * x + y * y < 1.0) ? 1UL : 0UL;
v += r;
v2 += r * r;
}
var mean = (double)v / (double)N;
var varc = ((double)v2 / (double)N - mean * mean ) * ((double)N/(N-1UL)); // variance
var stdd = Math.Sqrt(varc); // std.dev, should be sqrt(Pi/4 (1-Pi/4))
var errr = stdd / Math.Sqrt(N);
Console.WriteLine($"Mean = {mean}, StdDev = {stdd}, Err = {errr}");
mean *= 4.0;
errr *= 4.0;
Console.WriteLine($"PI (1 sigma) = {mean - 1.0 * errr}...{mean + 1.0 * errr}");
Console.WriteLine($"PI (2 sigma) = {mean - 2.0 * errr}...{mean + 2.0 * errr}");
Console.WriteLine($"PI (3 sigma) = {mean - 3.0 * errr}...{mean + 3.0 * errr}");
}
}
}
После 109 образцов я получил
Mean = 0.785405665, StdDev = 0.410540627166729, Err = 1.29824345388086E-05
PI (1 sigma) = 3.14157073026184...3.14167458973816
PI (2 sigma) = 3.14151880052369...3.14172651947631
PI (3 sigma) = 3.14146687078553...3.14177844921447
что выглядит примерно правильно. Легко видеть, что в идеальном случае дисперсия была бы равна (Pi/4)*(1-Pi/4). На самом деле нет необходимости вычислять v2
, просто установите его в v
после симуляции.
Я, честно говоря, не знаю, почему вы получаете не то, что ожидали. Потеря точности при суммировании может быть ответом, или, как я подозреваю, ваше моделирование не создает независимых выборок из-за заполнения и перекрывающихся последовательностей (поэтому фактическое N намного ниже 900 триллионов).
Но с помощью этого метода вы контролируете ошибку и проверяете, как идут вычисления.
ОБНОВИТЬ
Я подставил ваши цифры, чтобы показать, что вы явно недооцениваете значение. Код
N = 893_547_800_000UL;
v = 701_766_448_388UL;
v2 = v;
var mean = (double)v / (double)N;
var varc = ((double)v2 / (double)N - mean * mean ) * ((double)N/(N-1UL));
var stdd = Math.Sqrt(varc); // should be sqrt(Pi/4 (1-Pi/4))
var errr = stdd / Math.Sqrt(N);
Console.WriteLine($"Mean = {mean}, StdDev = {stdd}, Err = {errr}");
mean *= 4.0;
errr *= 4.0;
Console.WriteLine($"PI (1 sigma) = {mean - 1.0 * errr}...{mean + 1.0 * errr}");
Console.WriteLine($"PI (2 sigma) = {mean - 2.0 * errr}...{mean + 2.0 * errr}");
Console.WriteLine($"PI (3 sigma) = {mean - 3.0 * errr}...{mean + 3.0 * errr}");
И вывод
Mean = 0.785370909522692, StdDev = 0.410564786603016, Err = 4.34332975349809E-07
PI (1 sigma) = 3.14148190075886...3.14148537542267
PI (2 sigma) = 3.14148016342696...3.14148711275457
PI (3 sigma) = 3.14147842609506...3.14148885008647
Итак, у вас явно есть проблема (код? Потеря точности в представлении? Потеря точности при суммировании? Повторная/независимая выборка?)
person
Severin Pappadeux
schedule
13.09.2018
Math.random()
может быть не лучшим генератором случайных чисел. - person meowgoesthedog   schedule 12.09.2018size
? В любом случае ошибка оценки примерно пропорциональна величине, обратной квадратному корню из размера выборки. Когда вы переходите от 1 миллиона к 1 триллиону, размер выборки увеличивается в миллион раз, но только в тысячу раз увеличивается квадратный корень из размера выборки. Который -- должен купить вам еще 2 или 3 знака после запятой точности. Это не означает, что в коде нет ошибки, но то, что вы видите, может быть не таким удивительным, как вы думаете. - person John Coleman   schedule 13.09.2018