Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions Sources/AngouriMath/Functions/InternalAMExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1245,17 +1245,24 @@ internal static EDecimal[] GetSpougeFactorialConstants(int a)

constants[0] = EDecimal.PI(mc).Multiply(2, mc).Sqrt(mc);

var negative = false;
// c_k = (-1)^(k - 1) (a - k)^(k - 1)/(k - 1)! sqrt(a - k) e^(a - k), the first factor a ratio of exact
// integers and e^(a - k) a product of e's, with digits to spare for the a multiplications that make it.
// With a power of a - k to k - 1/2 and an exponential for each k, the constants for 300 digits took 20
// seconds, and for 600 digits 218.
var work = EContext.ForPrecision(a * 15 / 10 + 10);
var e = EDecimal.One.Exp(work);
var powersOfE = new EDecimal[a];
powersOfE[0] = EDecimal.One;
for (int m = 1; m < a; m++)
powersOfE[m] = powersOfE[m - 1].Multiply(e, work);
for (int k = 1; k < a; k++)
{
var deltaAK = EDecimal.FromInt32(a - k);
var ck = deltaAK.Pow(EDecimal.FromInt32(k).Subtract(0.5m), mc);
ck = deltaAK.Exp(mc).Multiply(ck, mc);
ck = ck.Divide(Factorial(k - 1), mc);
if (negative)
ck = ck.Negate();
constants[k] = ck;
negative = !negative;
var m = a - k;
var ck = EDecimal.FromEInteger(EInteger.FromInt32(m).Pow(k - 1)).Divide(EDecimal.FromEInteger(Factorial(k - 1)), work)
.Multiply(EDecimal.FromInt32(m).Sqrt(work), work)
.Multiply(powersOfE[m], work)
.RoundToPrecision(mc);
constants[k] = k % 2 == 0 ? ck.Negate() : ck;
}

return constants;
Expand Down
20 changes: 19 additions & 1 deletion Sources/Tests/UnitTests/Core/FactorialFarFromZeroTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//
//
// Copyright (c) 2019-2026 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
Expand Down Expand Up @@ -78,6 +78,24 @@ public void ADivisorsModulusNearAWholeNumberIsNotRoundedToIt()
Close("-0.002993872340987814525483818825494753213055396187438519990678101458851071", value.ImaginaryPart.EDecimal, 60);
}

/// <summary>
/// At 300 digits, on the real line and off it. Spouge's 390 constants were made with a power and an exponential
/// each, and the first factorial at that precision took 20 seconds; they are a ratio of integers, a square root and
/// a product of <c>e</c>'s now.
/// </summary>
[Fact]
public void AtThreeHundredDigits()
{
var context = EContext.ForPrecision(300);
Close("0.89297951156924921121856431365822588137622979265243370031680944253013920338924793984699429634706292980638634973335742111190636152316815741999257112256948992272242994101666773944751677408238564727251848331757626146492648043525527613387077304719882217534457586134019354517131441367733861313846090028508017368",
Evaluate("(1/3)!", context).RealPart.EDecimal, 295);
var value = Evaluate("(1/3 + i)!", context);
Close("0.55310533708451368643420143855148996023577256508846542223376506819123717723035945992089147907370521801219397887942272059738687781730094054546525636372408182990085240891013953705988378166744479672870436455961985418938874599630727253813312731648659256268261654562175265755195218626689594794087234395264053064",
value.RealPart.EDecimal, 295);
Close("0.0097530148049768242524751667053160295250646412881078165005696874705860541880090280173509525760804027158706765197226375317213454843960898145149813764056673011748957471092198259369271410261828558753507851947578513569017247888018679994921424076865568363297838883827120115940210102202849352569014259005743340527",
value.ImaginaryPart.EDecimal, 293);
}

/// <summary>The reflection formula off the real line, which the complex factorial now takes left of zero.</summary>
[Fact]
public void LeftOfZeroOffTheRealLine()
Expand Down
Loading