// Computes (S(x + y) - S(x)) / y, i.e. the rate at which S(x + y) - S(x) changes with y private static double ReducedPochhammerSum(double x, double y) { double L = MoreMath.ReducedLogOnePlus(1.0 / x, y); double xx = x * x; double xk = x; double f = AdvancedIntegerMath.Bernoulli[1] / (2.0 * xk) * MoreMath.ReducedExpMinusOne(-L, y); for (int k = 2; k < AdvancedIntegerMath.Bernoulli.Length; k++) { double f_old = f; xk *= xx; f += AdvancedIntegerMath.Bernoulli[k] / ((2 * k) * (2 * k - 1)) / xk * MoreMath.ReducedExpMinusOne((1 - 2 * k) * L, y); if (f == f_old) { return(f); } } throw new NonconvergenceException(); }
protected override object HandleAngleConverting(object value) { double?doubleValueNullable = ParsingUtilities.ParseDoubleNullable(value); if (!doubleValueNullable.HasValue) { return(value); } double doubleValue = doubleValueNullable.Value; if (_truncateToMultipleOf16) { doubleValue = MoreMath.TruncateToMultipleOf16(doubleValue); } doubleValue = MoreMath.NormalizeAngleUsingType(doubleValue, _effectiveType); doubleValue = (doubleValue / 65536) * GetAngleUnitTypeMaxValue(); return(doubleValue); }
private static Complex ComplexSqrt(Complex z) { // We could just call Pow(z, 0.5), but that is slow (involves multiple trig functions) // and looses a bit of symmetry (e.g. square roots of pure negative numbers may have tiny real parts because Pi is not exact) // Instead we expand (x + i y)^2 = a + i b to obtain a quadratic equations in x^2 and y^2. Solving (and thinking a bit about signs) yields // x = \sqrt{\frac{m + a}{2}} // y = \pm \sqrt{\frac{m - a}{2}} // where m = |a + i b| = \sqrt{a^2 + b^2} // Using this is very straightforward unless |b| << |a|, in which case m ~ |a| and there is a near-cancelation in one of the expressions. // In this case we pull out a factor a and use a series expansion of \sqrt{1 + w} - 1 where w = (b/a)^2. // In the end the whole algorithm is a little bit more complicated than I would like, but it is much faster than Pow(z, 0.5). double x, y; if (Math.Abs(z.Im) < Math.Abs(z.Re) / 8.0) { double s = Series1(MoreMath.Sqr(z.Im / z.Re)); if (z.Re > 0.0) { x = Math.Sqrt(z.Re * (s + 2.0) / 2.0); y = Math.Sqrt(z.Re * s / 2.0); } else { x = Math.Sqrt(-z.Re * s / 2.0); y = Math.Sqrt(-z.Re * (s + 2.0) / 2.0); } } else { double m = MoreMath.Hypot(z.Re, z.Im); x = Math.Sqrt((m + z.Re) / 2.0); y = Math.Sqrt((m - z.Re) / 2.0); } if (z.Im < 0.0) { y = -y; } return(new Complex(x, y)); }
/// <summary> /// Computes the dilogarathm function, also called Spence's function. /// </summary> /// <param name="x">The argument, which must be less than or equal to unity.</param> /// <returns>The value Li<sub>2</sub>(x).</returns> /// <remarks> /// <para>The dilogarithm can be defined by an infinite sum.</para> /// <img src="../images/DilogSum.png" /> /// <para>The function gets is name from the similarity of this series to the expansion of ln(1-x), the /// difference being that the integer in the denominator is raised to the second power.</para> /// <para>Li<sub>2</sub>(x) is real for -∞ < x ≤ 1; for values outside this range, /// use the complex version <see cref="AdvancedComplexMath.DiLog"/>.</para> /// </remarks> /// <seealso cref="AdvancedComplexMath.DiLog" /> /// <seealso href="http://en.wikipedia.org/wiki/Dilogarithm" /> public static double DiLog(double x) { if (x > 1.0) { throw new ArgumentOutOfRangeException(nameof(x)); } else if (x > 0.625) { // use Li(x) + Li(1-x) = \frac{\pi^2}{6} - \log x \log (1-x) // to map x near 1 to x near 0 if (x == 1.0) { // Special case x = 1 exactly to avoid computing log(0). return(Math.PI * Math.PI / 6.0); } else { return(Math.PI * Math.PI / 6.0 - DiLog_Series(1.0 - x) - Math.Log(x) * MoreMath.LogOnePlus(-x)); } // use series near 1 //return (DiLog_Series_1(1.0 - x)); } else if (x > -0.625) { // series near 0 (defining power series) return(DiLog_Series(x)); } else if (x >= -1.0) { // Use Li(x) + Li(-x) = \frac{1}{2} Li(x^2) // to map negative x to positive x return(0.5 * DiLog(x * x) - DiLog(-x)); } else if (x >= Double.NegativeInfinity) { // use formula for Li(1/x) to map to [-1,0] return(-Math.PI * Math.PI / 6.0 - 0.5 * MoreMath.Sqr(Math.Log(-x)) - DiLog(1.0 / x)); } else { return(Double.NaN); } }
private double ComputeDeficit(double[] z, ref double[] r) { double r2 = 0.0; for (int i = 0; i < r.Length; i++) { r[i] = -g[i]; for (int j = 0; j <= i; j++) { r[i] -= h[i][j] * z[j]; } for (int j = i; j < z.Length; j++) { r[i] -= h[j][i] * z[j]; } r2 += MoreMath.Sqr(r[i]); } return(r2); }
// Cumulants K_r = \frac{q E_{r-1}(q)}{p^r} (also Eulerian polynomials but not quite same // as raw moments). See Shenton & Bowman, "The Geometric Distribution's Central Moments // and Eulerian Numbers of the Second Kind", Far East J. Theo. Stat. 7 (1) 2002 1-17 // (http://www.csm.ornl.gov/~bowman/fjts7.pdf) /// <inheritdoc /> public override double Cumulant(int r) { if (r < 0) { throw new ArgumentOutOfRangeException(nameof(r)); } else if (r == 0) { return(0.0); } else if (r == 1) { return(q / p); } else { return(q * EulerianPolynomial(r - 1, q) / MoreMath.Pow(p, r)); } }
public void SumOfPowers() { // This test is difficult because the minimum is emphatically not quadratic. // We do get close to the minimum but we massivly underestimate our error. Func <IList <double>, double> function = (IList <double> x) => { double s = 0.0; for (int i = 0; i < x.Count; i++) { s += MoreMath.Pow(Math.Abs(x[i]), i + 2); } return(s); }; for (int n = 2; n < 8; n++) { Console.WriteLine(n); ColumnVector start = new ColumnVector(n); for (int i = 0; i < n; i++) { start[i] = 1.0; } EvaluationSettings settings = new EvaluationSettings() { AbsolutePrecision = 1.0E-8, EvaluationBudget = 32 * n * n * n }; MultiExtremum minimum = MultiFunctionMath.FindLocalMinimum(function, start, settings); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine("{0} {1}", minimum.Value, minimum.Precision); Console.WriteLine("|| {0} {1} ... || = {2}", minimum.Location[0], minimum.Location[1], minimum.Location.FrobeniusNorm()); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Value, 0.0, new EvaluationSettings() { AbsolutePrecision = 1.0E-4 })); //Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Location, new ColumnVector(n), new EvaluationSettings() { AbsolutePrecision = 1.0E-2 })); } }
public void ChangeModel(List <short[]> vertices, List <int[]> triangles) { ManualMode = false; var maxRadius = vertices.Max(v => MoreMath.GetDistanceBetween(v[0], v[2], 0, 0)); var maxHeight = vertices.Max(v => v[1]); var minHeight = vertices.Min(v => v[1]); _cameraHeight = maxHeight + (float)(Math.Sqrt(2) * maxRadius); _cameraRadius = (float)maxRadius * 2f; _modelCenter = new Vector3(0, (maxHeight + minHeight) / 2, 0); _modelRadius = vertices.Max(v => (new Vector3(v[0], v[1], v[2]) - _modelCenter).Length); _zoom = -0.57735026919f; // 60 degree FOV lock (_modelLock) { // Create vertice point vectors _vertices = new Vector3[vertices.Count]; for (int i = 0; i < _vertices.Length; i++) { _vertices[i] = new Vector3(vertices[i][0], vertices[i][1], vertices[i][2]); } // Create triangle _triangles = new int[triangles.Count][]; _triangleColors = new Color[triangles.Count]; for (int i = 0; i < _triangles.Length; i++) { // Make sure vertices exist _triangles[i] = triangles[i].Select(t => t >= _vertices.Length || t < 0 ? 0 : t).ToArray(); // Find triangle colors var tri = _triangles[i]; _triangleColors[i] = ColorFromTri(_vertices[tri[0]], _vertices[tri[1]], _vertices[tri[2]]); } // Unselect all triangle and vertices _vertexSelected = new bool[_vertices.Length]; _triangleSelected = new bool[_triangles.Length]; } }
private void CoulombRecursionTest(int L, double eta, double rho) { SolutionPair sm = AdvancedMath.Coulomb(L - 1, eta, rho); SolutionPair s0 = AdvancedMath.Coulomb(L, eta, rho); SolutionPair sp = AdvancedMath.Coulomb(L + 1, eta, rho); double eps = 8.0 * TestUtilities.TargetPrecision; // Relating u_{L}' to u_{L-1} and u_{L} Assert.IsTrue(TestUtilities.IsSumNearlyEqual( MoreMath.Hypot(L, eta) * sm.FirstSolutionValue, -(L * L / rho + eta) * s0.FirstSolutionValue, L * s0.FirstSolutionDerivative, eps )); Assert.IsTrue(TestUtilities.IsSumNearlyEqual( MoreMath.Hypot(L, eta) * sm.SecondSolutionValue, -(L * L / rho + eta) * s0.SecondSolutionValue, L * s0.SecondSolutionDerivative, eps )); // Relating u_{L}' to u_{L} and u_{L+1} // Relating u_{L+1}, u_{L}, u_{L-1} Assert.IsTrue(TestUtilities.IsSumNearlyEqual( (2 * L + 1) * (eta + L * (L + 1) / rho) * s0.FirstSolutionValue, -(L + 1) * MoreMath.Hypot(L, eta) * sm.FirstSolutionValue, L * MoreMath.Hypot(L + 1, eta) * sp.FirstSolutionValue, eps )); Assert.IsTrue(TestUtilities.IsSumNearlyEqual( (2 * L + 1) * (eta + L * (L + 1) / rho) * s0.SecondSolutionValue, -(L + 1) * MoreMath.Hypot(L, eta) * sm.SecondSolutionValue, L * MoreMath.Hypot(L + 1, eta) * sp.SecondSolutionValue, eps )); }
// This implements Fukushima's method of computing the Jacobian elliptic functions // sn, cn, and dn. The method is essentially to use range reduction to move u into // the range -K/2 < u < K/2, then repeatedly halve that value of u until it gets // small enough to apply the Maclaurin series for small m to compute sn, then // using the doubling formula to get back to the value of u required. /// <summary> /// Computes the Jacobian elliptic function sn. /// </summary> /// <param name="u">The argument.</param> /// <param name="k">The modulus, which must be between 0 and 1.</param> /// <returns>The value of sn(u,k).</returns> /// <exception cref="ArgumentOutOfRangeException"><paramref name="k"/> lies outside [0, 1].</exception> /// <remarks> /// <para>Be aware that some authors use the parameter m = k^2 instead of the modulus k.</para> /// </remarks> /// <seealso href="https://en.wikipedia.org/wiki/Jacobi_elliptic_functions"/> /// <seealso href="http://mathworld.wolfram.com/JacobiEllipticFunctions.html"/> /// <seealso href="http://dlmf.nist.gov/22"/> public static double JacobiSn(double u, double k) { if (u < 0.0) { return(-JacobiSn(-u, k)); } if ((k < 0.0) || (k > 1.0)) { throw new ArgumentOutOfRangeException(nameof(k)); } // For k=1, K is infinite and our reduction algorithm breaks down. // But even for k = 1-10^(-16), K~19.4 and the reduction works fine, // so we only need to do this at exactly k=1. if (k == 1.0) { return(Math.Tanh(u)); } // Decompose u = u_0 K + u_1, where -K/2 < u_1 < K/2, and compute sn(u_1) long u0; double u1; double sn = JacobiSn_ViaRangeReduction(u, k, out u0, out u1); // Transform to the appropriate quadrant switch (MoreMath.Mod(u0, 4)) { case 0: return(sn); case 1: return(Math.Sqrt((1.0 - sn * sn) / (1.0 - MoreMath.Sqr(k * sn)))); case 2: return(-sn); case 3: return(-Math.Sqrt((1.0 - sn * sn) / (1.0 - MoreMath.Sqr(k * sn)))); default: throw new InvalidOperationException(); } }
protected override List <(float x, float y, float z)> GetGridlineIntersectionPositionsTopDownView() { if (_setting != PuGridlineSetting.SETTING1) { return(new List <(float x, float y, float z)>()); } float marioY = Config.Stream.GetFloat(MarioConfig.StructAddress + MarioConfig.YOffset); long size = (long)Math.Max(Size, 1); long spacing = (long)(puSize * size); long xOffset = 0; long zOffset = 0; long xOffsetReverse = 0; long zOffsetReverse = 0; if (_useMarioAsOrigin) { (int puXIndex, int puYIndex, int puZIndex) = PuUtilities.GetMarioPuIndexes(); xOffset = (long)MoreMath.NonNegativeModulus(puXIndex, size); zOffset = (long)MoreMath.NonNegativeModulus(puZIndex, size); xOffsetReverse = size - xOffset; zOffsetReverse = size - zOffset; } long xMin = ((((long)Config.CurrentMapGraphics.MapViewXMin) / spacing) - 1) * spacing - puSize * xOffsetReverse; long xMax = ((((long)Config.CurrentMapGraphics.MapViewXMax) / spacing) + 1) * spacing + puSize * xOffset; long zMin = ((((long)Config.CurrentMapGraphics.MapViewZMin) / spacing) - 1) * spacing - puSize * zOffsetReverse; long zMax = ((((long)Config.CurrentMapGraphics.MapViewZMax) / spacing) + 1) * spacing + puSize * zOffset; List <(float x, float y, float z)> vertices = new List <(float x, float y, float z)>(); for (long x = xMin; x <= xMax; x += spacing) { for (long z = zMin; z <= zMax; z += spacing) { vertices.Add((x, marioY, z)); } } return(vertices); }
/// <inheritdoc /> public override double Cumulant(int r) { if (r < 0) { throw new ArgumentOutOfRangeException("r"); } else if (r == 0) { return(0.0); } else if (r == 1) { return(Mean); } else { // K_{r+1} = \frac{(2 r)!}{2^r r! \mu^{2r+1} \lambda^r} = \frac{(2r - 1)!! \mu^{2r+1}}{\lambda^r} return(AdvancedIntegerMath.DoubleFactorial(2 * r - 3) * MoreMath.Pow(mu, 2 * r - 1) / MoreMath.Pow(lambda, r - 1)); } }
public void EllipticPiIntegration() { Interval i = Interval.FromEndpoints(0.0, Math.PI / 2.0); foreach (double k in TestUtilities.GenerateRealValues(1.0E-2, 1.0, 4)) { double m = k * k; foreach (double n in TestUtilities.GenerateUniformRealValues(-2.0, 1.0, 4)) { Func <double, double> f = delegate(double t) { double s2 = MoreMath.Sqr(Math.Sin(t)); return(1.0 / (1.0 - n * s2) / Math.Sqrt(1.0 - m * s2)); }; Assert.IsTrue(TestUtilities.IsNearlyEqual( FunctionMath.Integrate(f, i), AdvancedMath.EllipticPi(n, k) )); } } }
internal PrincipalComponentAnalysis(double[] utStore, double[] wStore, double[] vStore, int rows, int cols) { Debug.Assert(utStore != null); Debug.Assert(wStore != null); Debug.Assert(vStore != null); Debug.Assert(rows > 0); Debug.Assert(cols > 0); this.rows = rows; this.cols = cols; this.utStore = utStore; this.wStore = wStore; this.vStore = vStore; // keep track of cumulative sum of squares, which is proportional to the cumulative explained variance wSquaredSum = new double[wStore.Length]; wSquaredSum[0] = MoreMath.Sqr(wStore[0]); for (int i = 1; i < wSquaredSum.Length; i++) { wSquaredSum[i] = wSquaredSum[i - 1] + MoreMath.Sqr(wStore[i]); } }
// Abromowitz & Stegun 7.8.3 // Cl_2(\pi - \theta) = \theta \log 2 - \sum_{k=1}^{\infty} \frac{|B_{2k}| (2^2k - 1) \theta^{2k+1}}{(2k!) (2k) (2k+1)} // Because of the additional factor 2^{2k} in numerator, this series converges much slower than the series around 0. // If we transition between the two of them at \pi/2, this series takes about 30 terms while the other takes only 10. // If we transition between the two of them at 2\pi/3, each takes about 15 terms. private static double ClausenNearPi(double t) { double f = Global.LogTwo; double t2 = t * t; double sk = 1.0; // tracks t^2k / k! for (int k = 1; k < AdvancedIntegerMath.Bernoulli.Length; k++) { double f_old = f; int tk = 2 * k; sk *= t2 / tk / (tk - 1); f -= Math.Abs(AdvancedIntegerMath.Bernoulli[k]) * (MoreMath.Pow(4.0, k) - 1.0) * sk / tk / (tk + 1); if (f == f_old) { return(t * f); } } throw new NonconvergenceException(); }
/** Add +1/-1 with probability of p */ static int mutateIntOne(int x, int min, int max, float p) { if (Random.value < p) { int y = x; if (Random.Range(0, 2) == 0) { y--; } else { y++; } return(MoreMath.Clamp(min, max, y)); } else { return(x); } }
public void ThreeHumpCamel() { // This function has three local minima, so not at all starting points should be expected to bring us to the global minimum at the origin. Func <IList <double>, double> function = (IList <double> x) => 2.0 * MoreMath.Pow(x[0], 2) - 1.05 * MoreMath.Pow(x[0], 4) + MoreMath.Pow(x[0], 6) / 6.0 + x[0] * x[1] + MoreMath.Pow(x[1], 2); ColumnVector start = new ColumnVector(1.0, 1.0); MultiExtremum minimum = MultiFunctionMath.FindLocalMinimum(function, start); Console.WriteLine("{0} ({1}) ?= 0.0", minimum.Value, minimum.Precision); Console.WriteLine("{0} {1}", minimum.Location[0], minimum.Location[1]); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Value, 0.0, new EvaluationSettings() { AbsolutePrecision = 2.0 * minimum.Precision })); Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Location, new ColumnVector(2), new EvaluationSettings { AbsolutePrecision = 2.0 * Math.Sqrt(minimum.Precision) })); }
/// <summary> /// Computes the digamma function. /// </summary> /// <param name="x">The argument.</param> /// <returns>The value of ψ(x).</returns> /// <remarks> /// <para>The psi function, also called the digamma function, is the logrithmic derivative of the Γ function.</para> /// <img src="../images/DiGamma.png" /> /// <para>Because it is defined as a <i>logarithmic</i> derivative, the digamma function does not overflow <see cref="System.Double"/> /// even for arguments for which <see cref="Gamma(double)"/> does.</para> /// <para>To evaluate the psi function for complex arguments, use <see cref="AdvancedComplexMath.Psi" />.</para> /// </remarks> /// <seealso cref="Gamma(double)"/> /// <seealso cref="AdvancedComplexMath.Psi"/> /// <seealso href="http://en.wikipedia.org/wiki/Digamma_function" /> /// <seealso href="http://mathworld.wolfram.com/DigammaFunction.html" /> public static double Psi(double x) { if (x < 0.25) { return(Psi(1.0 - x) - Math.PI / MoreMath.TanPi(x)); } else if (x < 16.0) { return(Lanczos.Psi(x)); } else if (x <= Double.PositiveInfinity) { // For large arguments, the Stirling asymptotic expansion is faster than the Lanzcos approximation return(Stirling.Psi(x)); } else { return(Double.NaN); } }
/// <inheritdoc /> public override double ProbabilityMass(int k) { if (k < 0) { return(0.0); } else { // These are the same expression, but the form for small arguments is faster, // while the form for large arguments avoids overflow and cancellation errors. if (k < 16) { return(Math.Exp(-mu) * MoreMath.Pow(mu, k) / AdvancedIntegerMath.Factorial(k)); } else { return(Stirling.PoissonProbability(mu, k)); } } }
/// <inheritdoc /> public override double CentralMoment(int r) { if (r < 0) { throw new ArgumentOutOfRangeException(nameof(r)); } else if (r == 0) { return(1.0); } else if ((r % 2) == 0) { // (r-1)!! \sigma^r return(AdvancedIntegerMath.DoubleFactorial(r - 1) * MoreMath.Pow(sigma, r)); } else { return(0.0); } }
public void OdeNonlinear() { // y = \frac{y_0}{1 - y_0 (x - x_0)} Func <double, double, double> f = (double x, double y) => MoreMath.Sqr(y); int count = 0; OdeSettings settings = new OdeSettings() { RelativePrecision = 1.0E-8, EvaluationBudget = 1024, Listener = (OdeResult) => count++ }; OdeResult result = FunctionMath.IntegrateOde(f, 0.0, 1.0, 0.99, settings); Assert.IsTrue(TestUtilities.IsNearlyEqual(result.Y, 1.0 / (1.0 - 1.0 * (0.99 - 0.0)), result.Settings)); Assert.IsTrue(count > 0); Console.WriteLine(result.EvaluationCount); }
public void BinomialCoefficientSums() { foreach (int n in TestUtilities.GenerateIntegerValues(1, 100, 8)) { double S0 = 0.0; double S1 = 0.0; double S2 = 0.0; int k = 0; foreach (double B in AdvancedIntegerMath.BinomialCoefficients(n)) { S0 += B; S1 += k * B; S2 += k * k * B; k += 1; } Assert.IsTrue(TestUtilities.IsNearlyEqual(S0, MoreMath.Pow(2, n))); Assert.IsTrue(TestUtilities.IsNearlyEqual(S1, MoreMath.Pow(2, n - 1) * n)); Assert.IsTrue(TestUtilities.IsNearlyEqual(S2, MoreMath.Pow(2, n - 2) * n * (n + 1))); } }
/// <inheritdoc /> public override double RawMoment(int r) { if (r < 0) { throw new ArgumentOutOfRangeException(nameof(r)); } else if (r == 0) { return(1.0); } else if (r >= a) { return(Double.PositiveInfinity); } else { // Straightforward integration yields M_r = \frac{\alpha m^r}{\alpha - r} return(a / (a - r) * MoreMath.Pow(m, r)); } }
/// <summary> /// Gets a central moment of the distribution. /// </summary> /// <param name="r">The order of the moment.</param> /// <returns>The central moment C<sub>r</sub>.</returns> public override double CentralMoment(int r) { if (r < 0) { throw new ArgumentOutOfRangeException(nameof(r)); } else if (r == 0) { return(1.0); } else if (r == 1) { return(0.0); } else { double mu = Mean; return(ExpectationValue((int k) => MoreMath.Pow(k - mu, r))); } }
public override MapObjectHoverData GetHoverDataTopDownView(bool isForObjectDrag, bool forceCursorPosition) { Point?relPosMaybe = MapObjectHoverData.GetPositionMaybe(isForObjectDrag, forceCursorPosition); if (!relPosMaybe.HasValue) { return(null); } Point relPos = relPosMaybe.Value; (float inGameX, float inGameY, float inGameZ) = GetArrowHeadPosition(); (double controlX, double controlZ) = MapUtilities.ConvertCoordsForControlTopDownView(inGameX, inGameZ, UseRelativeCoordinates); double dist = MoreMath.GetDistanceBetween(controlX, controlZ, relPos.X, relPos.Y); if (dist <= 20 || forceCursorPosition) { return(new MapObjectHoverData(this, inGameX, inGameY, inGameZ)); } return(null); }
/// <inheritdoc /> public override double GetRandomValue(Random rng) { // This is a rather weird transformation generator described in Michael et al, "Generating Random Variates // Using Transformations with Multiple Roots", The American Statistician 30 (1976) 88-90. double u = rngGenerator.GetNext(rng); double y = MoreMath.Sqr(rngGenerator.GetNext(rng)); double muy = mu * y; double x = mu * (1.0 + (muy - Math.Sqrt((4.0 * lambda + muy) * muy)) / (2.0 * lambda)); double z = rng.NextDouble(); if (z <= mu / (mu + x)) { return(x); } else { return(mu * mu / x); } }
// update_walking_speed private static void UpdateWalkingSpeed(MutableMarioState marioState) { float maxTargetSpeed; float targetSpeed; bool slowSurface = false; if (slowSurface) { maxTargetSpeed = 24.0f; } else { maxTargetSpeed = 32.0f; } targetSpeed = marioState.IntendedMagnitude < maxTargetSpeed ? marioState.IntendedMagnitude : maxTargetSpeed; if (marioState.HSpeed <= 0.0f) { marioState.HSpeed += 1.1f; } else if (marioState.HSpeed <= targetSpeed) { marioState.HSpeed += 1.1f - marioState.HSpeed / 43.0f; } else { marioState.HSpeed -= 1.0f; } if (marioState.HSpeed > 48.0f) { marioState.HSpeed = 48.0f; } marioState.MarioAngle = MoreMath.NormalizeAngleUshort( marioState.IntendedAngle - CalculatorUtilities.ApproachInt( MoreMath.NormalizeAngleShort(marioState.IntendedAngle - marioState.MarioAngle), 0, 0x800, 0x800)); ApplySlopeAccel(marioState); }
/// <summary> /// Computes the exponential integral. /// </summary> /// <param name="n">The order parameter.</param> /// <param name="x">The argument, which must be non-negative.</param> /// <returns>The value of E<sub>n</sub>(x).</returns> /// <remarks> /// <para>The exponential integral is defined as:</para> /// <img src="../images/EIntegral.png" /> /// <para>It is related to the incomplete Gamma function for negative, integer shape parameters by Γ(-k, x) = Ei<sub>k+1</sub>(x) / x<sup>k</sup>.</para> /// <para>In hydrology, E<sub>1</sub>(x) is sometimes called the Well function.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="x"/> is negative.</exception> public static double IntegralE(int n, double x) { if (x < 0.0) { throw new ArgumentOutOfRangeException("x"); } // special case x = 0 if (x == 0.0) { if (n <= 1) { return(Double.PositiveInfinity); } else { return(1.0 / (n - 1)); } } if (n < 0) { // negative n is expressible using incomplete Gamma return(AdvancedMath.Gamma(1 - n, x) / MoreMath.Pow(x, 1 - n)); } else if (n == 0) { // special case n=0 return(Math.Exp(-x) / x); } else if (x < 2.0) { // use series for x < 1 return(IntegralE_Series(n, x)); } else { // use continued fraction for x > 1 return(IntegralE_ContinuedFraction(n, x)); } }
/// <summary> /// Computes a Stirling number of the second kind. /// </summary> /// <param name="n">The upper argument, which must be non-negative.</param> /// <param name="k">The lower argument, which must lie between 0 and n.</param> /// <returns>The value of the Stirling number of the second kind.</returns> /// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is negative, or <paramref name="k"/> /// lies outside [0, n].</exception> /// <seealso href="https://en.wikipedia.org/wiki/Stirling_numbers_of_the_second_kind"/> public static double StirlingNumber2(int n, int k) { if (n < 0) { throw new ArgumentOutOfRangeException(nameof(n)); } if ((k < 0) || (k > n)) { throw new ArgumentOutOfRangeException(nameof(k)); } if ((k == 1) || (k == n)) { return(1.0); } else if (k == 0) { return(0.0); // The exceptional value 1 for n = k = 0 will already have been returned by the previous case. } else if (k == 2) { return(Math.Round(MoreMath.Pow(2.0, n - 1) - 1.0)); } else if (k == (n - 1)) { return(AdvancedIntegerMath.BinomialCoefficient(n, 2)); } else { double[] s = Stirling2_Recursive(n, k); return(s[k]); } // There is a formula for Stirling numbers // { n \brace k } = \frac{1}{k!} \sum{j=0}^{k} (-1)^j { k \choose j} (k - j)^n // which would be faster than recursion, but it has large cancelations between // terms. We could try to use it when all values are less than 2^52, for which // double arithmetic is exact for integers. For k!, that means k < 18. For // largest term in sum for all k, that means n < 14. }
public void StylblinskiTang() { Func <IList <double>, double> fStyblinskiTang = (IList <double> x) => { double fst = 0.0; for (int i = 0; i < x.Count; i++) { double x1 = x[i]; double x2 = MoreMath.Sqr(x1); fst += x2 * (x2 - 16.0) + 5.0 * x1; } return(fst / 2.0); }; // solution coordinate is root of 5 - 32 x + 4 x^3 = 0 with negative second derivative. // There are two such roots. double root1 = -2.9035340277711770951; double root2 = 2.7468027709908369925; // tested up to n=16, works with slightly decreasing accuracy of Location for (int n = 2; n < 8; n++) { Console.WriteLine(n); ColumnVector start = new ColumnVector(n); //ColumnVector start = new ColumnVector(-1.0, -2.0, -3.0, -4.0, -5.0, -6.0); MultiExtremum minimum = MultiFunctionMath.FindLocalMinimum(fStyblinskiTang, start); Console.WriteLine(minimum.EvaluationCount); Console.WriteLine(minimum.Value); for (int i = 0; i < minimum.Dimension; i++) { Console.WriteLine(minimum.Location[i]); Assert.IsTrue( TestUtilities.IsNearlyEqual(minimum.Location[i], root1, Math.Sqrt(Math.Sqrt(TestUtilities.TargetPrecision))) || TestUtilities.IsNearlyEqual(minimum.Location[i], root2, Math.Sqrt(Math.Sqrt(TestUtilities.TargetPrecision))) ); } Assert.IsTrue(TestUtilities.IsNearlyEqual(minimum.Value, fStyblinskiTang(minimum.Location))); } }