В этой ситуации нужно подумать: «Предположим, у меня есть волшебный ящик c, который ответил на конкретный вопрос c, который я ему задал; каковы будут входы и выходы этого ящика?» и написать метод, который реализует этот блок .
Начните с самого простого блока. Нет входных данных, выходные данные - это равномерно распределенное число от нуля до единицы:
static Random random = new Random();
static double Uniform() => random.NextDouble();
ОК, теперь у нас есть новый инструмент в нашем наборе инструментов. Какая у нас следующая волшебная c коробка? Нет входных данных, выходной это нормально распределенное число со средним нулем и стандартным отклонением:
static double StandardNormal() =>
Sqrt(-2 * Log(Uniform())) * Cos(2 * PI * Uniform());
И у нас есть другой инструмент. Что мы можем построить с этим? Входы: среднее и стандартное отклонение, выход, нормально распределенное число с этим средним и стандартным отклонением:
static double Normal(double mean, double sigma) =>
sigma * StandardNormal() + mean;
Хорошо, теперь что нам нужно? Дисперсия как функция массы и температуры:
static double KB = 1.38064852e-23;
static double MaxwellVariance(double mass, double temperature) =>
Sqrt(KB * temperature / mass);
Супер, мы движемся прямо. Теперь что нам нужно? Входные данные - это масса и температура, выходные данные - это одна случайная максвелловская составляющая скорости:
static double MaxwellComponent(double mass, double temperature) =>
Normal(0.0, MaxwellVariance(mass, temperature));
Что нам теперь нужно? Тип для представления вектора:
struct Vector
{
public double X { get; }
public double Y { get; }
public double Z { get; }
public Vector(double x, double y, double z)
{
this.X = x;
this.Y = y;
thiz.Z = z;
}
}
Что нам нужно дальше? Случайный вектор:
static Vector MaxwellVector(double mass, double temperature) =>
...
Вы можете взять его отсюда? Что вам понадобится дальше? Снова продолжайте разбивать его на однострочники . Не увлекайся Нет премии за написание длинного кода, который вы не понимаете.
Техника здесь разделяй и властвуй . С этими проблемами вы почти всегда можете написать метод длиной менее пяти строк кода, который вычисляет только одну вещь . Так сделай это; вычислять только одну вещь каждый раз, и тогда у вас есть новый инструмент в вашем наборе инструментов для вычисления вещи next . Более того, у вас есть набор методов, каждый из которых (1), очевидно, корректен, потому что это всего лишь одна строка кода, и (2) тестируемый! Напишите набор тестов!
ОБНОВЛЕНИЕ: Вопрос был обновлен для реализации некоторых из этих идей, и выглядит он довольно неплохо. Есть дополнительный вопрос о температуре и массе.
Температура выглядит хорошо; 300K. Но масса совершенно не права. В инструкциях говорится, что нужно использовать массу одну молекулу , но вы ввели массу один моль молекул .
Помните, "моль" - это как "пара" или "дюжина". Пара - это две вещи, дюжина - двенадцать, моль - около 600000000000000000000000 вещей. Очевидно, молекула N2 не весит 28 граммов. Скорее 600000000000000000000000 молекул N2 весит 28 граммов.
Помните также, что метрические c единицы массы и объема были выбраны совершенно произвольно. Если вы возьмете окружность Земли, разделите ее на 4 миллиарда, сделайте коробку с кубиками c со сторонами этой длины и заполните ее водой - это масса одного грамма.
Мы выбрали значение, связанное с «моль», потому что оно обладает свойством, что моль молекулы того же типа имеет массу, равную массе атома c молекулы в граммах. Итак, в восемнадцати из этих маленьких коробочек есть один моль молекул воды. Использование молярной массы - это просто удобство, потому что это делает числа более «разумными» для наших целей; обычно мы привыкли думать о некотором количестве грамм воды, а не о каком-то количестве молекул воды, но ваша проблема касается только десяти тысяч молекул, а не десяти тысяч граммов. Итак, что вы хотите сделать, это разделить массу одного моля на количество вещей в моле, и это даст вам массу одной молекулы в граммах .
Следующая вещь сделать это сделать анализ единицы, чтобы определить, должна ли масса быть в граммах или килограммах! Для КБ мы имеем значение 1.38E-23, которое, как отмечает Википедия, имеет единицы Джоулей на Кельвин. Как мы это используем? Мы берем квадрат root КБ * Т / М. Какими единицами должен быть квадрат root? Это стандартное отклонение скорости , которое имеет единицы метров в секунду, поэтому нам нужно KB*T/M
, чтобы иметь квадраты метров в секунду в квадрате.
- КБ - Джоуль на Кельвин ; Это Кельвин, поэтому
KB * T
имеет единицы в Джоулях. - Джоули имеют единицы: килограмм метров в квадрате в секунду в квадрате.
- Поэтому, чтобы получить квадраты в метрах в секунду в квадрате нам нужно разделить на килограмм , а не грамм .
Так что вам нужно, граммы на моль, деленные на молекулы на моль, чтобы получить граммы на молекулу , а затем преобразовать это в килограммы на молекулу.
Имеет смысл? Привыкнуть проводить анализ единиц для каждой проблемы . Это уловило так много моих ошибок, когда я был студентом-физиком еще в темные века.
В сторону: Говоря об анализе единиц, кое-что, что следует быть осторожным: отрывок из вашего текста называет стандартное отклонение дисперсия , но стандартное отклонение фактически определяется как квадрат root дисперсии. Такое использование чрезвычайно распространено, и вы должны из контекста определить, означает ли «дисперсия» «действительно дисперсию» или, в данном случае, стандартное отклонение.
То есть текст должен сказать "N (μ, σ) - случайная величина с нормальным распределением с ожидаемым значением μ и дисперсией σ 2 ". Или следует сказать, что «N (μ, σ) является случайной величиной с нормальным распределением с ожидаемым значением μ и стандартным отклонением σ». Следите за этим и читайте с защитой.
Еще одно замечание: вы могли заметить, что способ представления дистрибутивов очень "неуклюжий". Такое чувство, что вам нужно проделать большую работу, чтобы представить что-то довольно простое. Мое текущее исследование в probabilisti c языках , которые делают этот вид работы очень простым. На вероятностном языке c мы бы представили ваш рабочий процесс примерно так:
IDistribution<double> Speed(double mass, double temp)
{
IDistribution<double> c =
Normal.Distribution(0.0, MaxwellVariance(mass, temp))
double x = sample c;
double y = sample c;
double z = sample c;
return Sqrt(x*x + y*y + z*z);
}
...
double mean = Speed(mass, temp).Mean(10000);
(Если это похоже на асинхронный метод c с заменой Task<T>
на IDistribution<T>
и заменой await
на sample
, это потому, что это так; и асинхронные, и вероятностные c рабочие процессы могут быть реализованы как сопрограммы.)
Если вас интересует тема вероятностных c языков, у меня есть небольшое, но продолжительное введение который начинается здесь: https://ericlippert.com/2019/01/31/fixing-random-part-1/