LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
fj_xmax_normal.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_FJ_XMAX_NORMAL_H
6#define LINE_API_FJ_XMAX_NORMAL_H
7
8/**
9 * @file
10 * @ingroup api_fj
11 * Expected maximum and variance of K i.i.d. normal samples.
12 *
13 * Templated port of matlab/src/api/fj/fj_xmax_normal.m, cross-checked against
14 * FJ_xmax.fj_xmax_normal in jar/src/main/java/jline/api/fj/FJ_xmax.java
15 * (identical).
16 *
17 * arnold: G(K) = sqrt(2 ln K)
18 * johnson: G(K) = sqrt(2 ln K) - (ln ln K - ln(4 pi) + 2 gamma)/(2 sqrt(2 ln K))
19 * corrected: johnson minus the Petzold bias 0.1727 K^-0.2750
20 * Var ~ 1.64492 sigma^2 / (2 ln K)
21 *
22 * static_assert(num_traits<T>::has_transcendental) -- log, sqrt and a real
23 * power throughout. Note ln ln K is -inf at K = 2 in MATLAB (ln 2 < 1 makes
24 * ln ln K finite and negative; it is K = 1 that diverges), and the function
25 * requires K >= 2 for that reason.
26 */
27
29#include "line/num/number.h"
30#include "line/util/error.h"
31
32namespace line {
33namespace fj {
34
35/**
36 * @brief Expected maximum and variance of K i.i.d. normal samples.
37 *
38 * @param K number of samples, K >= 2
39 * @param mu mean of the normal
40 * @param sigma standard deviation, >= 0
41 * @param method which correction to apply
42 * @return [Xmax, Vmax]
43 */
44template <class T>
45FJXmaxNormalResult<T> fj_xmax_normal(unsigned K, const T& mu, const T& sigma,
48 "fj_xmax_normal requires transcendental arithmetic");
49 if (K < 2) throw InputError("fj_xmax_normal: the normal approximation requires K >= 2");
50 if (sigma < num_traits<T>::from_int(0))
51 throw InputError("fj_xmax_normal: sigma must be non-negative");
52
53 const T two = num_traits<T>::from_int(2);
54 const T gamma_em = num_traits<T>::from_double(0.5772156649015329);
55 const T Kt = num_traits<T>::from_int(static_cast<long>(K));
56 const T lnK = detail::num_log(Kt);
57 const T sqrt_2lnK = detail::num_sqrt(T(two * lnK));
58
59 T GK = sqrt_2lnK;
60 if (method != FJNormalMethod::Arnold) {
61 const T corr = (detail::num_log(lnK) - detail::num_log(T(num_traits<T>::from_int(4) * detail::num_pi<T>())) +
62 two * gamma_em) /
63 (two * sqrt_2lnK);
64 GK = sqrt_2lnK - corr;
65 if (method == FJNormalMethod::Corrected)
66 GK -= num_traits<T>::from_double(0.1727) *
67 detail::num_pow(Kt, T(num_traits<T>::from_double(-0.2750)));
68 }
69 const T Xmax = mu + sigma * GK;
70 const T Vmax = num_traits<T>::from_double(1.64492) * sigma * sigma / (two * lnK);
71 return {Xmax, Vmax};
72}
73
74} // namespace fj
75} // namespace line
76
77#endif // LINE_API_FJ_XMAX_NORMAL_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Shared return types and arithmetic helpers for the templated fork-join port.
FJNormalMethod
Bracketing methods for the normal-maximum approximation.
Definition fj_types.h:44
FJXmaxNormalResult< T > fj_xmax_normal(unsigned K, const T &mu, const T &sigma, FJNormalMethod method=FJNormalMethod::Johnson)
Expected maximum and variance of K i.i.d.
Number-type abstraction for the templated API port.
[Xmax, Vmax] of fj_xmax_normal.
Definition fj_types.h:79