Skip to content

Commit 8516bcc

Browse files
committed
add factorial
1 parent c136f93 commit 8516bcc

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

source/mir/bignum/fp.d

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,21 @@ struct Fp(size_t coefficientSize, Exp = sizediff_t)
263263
assert(fp.coefficient == UInt!128.fromHexString("ffffffffffffffffffffffffffffffff"));
264264
}
265265

266+
/// ditto
267+
this(ulong value)
268+
{
269+
this(UInt!64(value));
270+
}
271+
272+
///
273+
this(long value)
274+
{
275+
this(ulong(value >= 0 ? value : -value));
276+
this.sign = !(value >= 0);
277+
}
278+
266279
///
267-
ref Fp opOpAssign(string op : "*")(Fp rhs) nothrow return
280+
ref Fp opOpAssign(string op : "*")(Fp rhs) nothrow scope return
268281
{
269282
this = this.opBinary!op(rhs);
270283
return this;

source/mir/math/numeric.d

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,3 +511,68 @@ unittest
511511
assert(isNaN(sumOfLog2s([-real.infinity])));
512512
assert(sumOfLog2s([ 0.25, 0.25, 0.25, 0.125 ]) == -9);
513513
}
514+
515+
/++
516+
Quickly computes factorial using extended
517+
precision floating point type $(MREF mir,bignum,fp).
518+
519+
Params:
520+
count = number of product members
521+
start = initial member value (optional)
522+
Returns: `(count + start - 1)! / (start - 1)!`
523+
+/
524+
auto factorial
525+
(size_t coefficientSize = 128, Exp = sizediff_t)
526+
(ulong count, ulong start = 1)
527+
if (coefficientSize % (size_t.sizeof * 8) == 0 && coefficientSize >= (size_t.sizeof * 8))
528+
in (start)
529+
{
530+
import mir.utility: _expect;
531+
import mir.bignum.fp: Fp;
532+
alias R = Fp!(coefficientSize, Exp);
533+
R prod = 1LU;
534+
import mir.checkedint: addu, mulu;
535+
536+
if (count)
537+
{
538+
ulong tempProd = start;
539+
while(--count)
540+
{
541+
bool overflow;
542+
ulong nextTempProd = mulu(tempProd, ++start, overflow);
543+
if (_expect(!overflow, true))
544+
{
545+
tempProd = nextTempProd;
546+
continue;
547+
}
548+
else
549+
{
550+
prod *= R(tempProd);
551+
tempProd = start;
552+
}
553+
}
554+
prod *= R(tempProd);
555+
}
556+
557+
return prod;
558+
}
559+
560+
///
561+
version(mir_test)
562+
@safe pure nothrow @nogc
563+
unittest
564+
{
565+
import mir.bignum.fp: Fp;
566+
import mir.math.common: approxEqual;
567+
import mir.math.numeric: prod;
568+
import mir.ndslice.topology: iota;
569+
570+
static assert(is(typeof(factorial(33)) == Fp!128));
571+
static assert(is(typeof(factorial!256(33)) == Fp!256));
572+
static assert(cast(double) factorial(33) == 8.68331761881188649551819440128e+36);
573+
574+
assert(cast(double) factorial(0) == 1);
575+
assert(cast(double) factorial(0, 100) == 1);
576+
assert(cast(double) factorial(1, 100) == 100);
577+
assert(approxEqual(cast(double) factorial(100, 1000), iota([100], 1000).prod!double));
578+
}

0 commit comments

Comments
 (0)