Skip to content

Commit 19c77bb

Browse files
committed
simplify binomialCoefficient
1 parent 8492de7 commit 19c77bb

File tree

2 files changed

+30
-31
lines changed

2 files changed

+30
-31
lines changed

source/mir/bignum/fp.d

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,8 @@ struct Fp(size_t coefficientSize, Exp = sizediff_t)
277277
}
278278

279279
///
280-
ref Fp opOpAssign(string op : "*")(Fp rhs) nothrow scope return
280+
ref Fp opOpAssign(string op)(Fp rhs) nothrow scope return
281+
if (op == "*" || op == "/")
281282
{
282283
this = this.opBinary!op(rhs);
283284
return this;
@@ -305,6 +306,19 @@ struct Fp(size_t coefficientSize, Exp = sizediff_t)
305306
assert(fp.coefficient == UInt!128.fromHexString("c6841dd302415d785373ab6d93712988"));
306307
}
307308

309+
/// Uses approximate division for now
310+
/// TODO: use full precision division for void when Fp division is ready
311+
Fp opBinary(string op : "/")(Fp rhs) nothrow const
312+
{
313+
Fp a = this;
314+
alias b = rhs;
315+
auto exponent = a.exponent - b.exponent;
316+
a.exponent = b.exponent = -coefficientSize;
317+
auto ret = Fp(cast(real) a / cast(real) b);
318+
ret.exponent += exponent;
319+
return ret;
320+
}
321+
308322
///
309323
T opCast(T)() nothrow const
310324
if (is(Unqual!T == bool))

source/mir/math/numeric.d

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -591,37 +591,22 @@ Params:
591591
Returns: n choose k
592592
Complexity: O(min(k, n - k))
593593
+/
594-
template binomialCoefficient(DivisionType = void)
595-
if (is(DivisionType == void) || __traits(isFloating, DivisionType))
594+
auto binomialCoefficient
595+
(size_t coefficientSize = 128, Exp = sizediff_t)
596+
(ulong n, uint k)
597+
if (coefficientSize % (size_t.sizeof * 8) == 0 && coefficientSize >= (size_t.sizeof * 8))
598+
in (k <= n)
596599
{
597-
auto binomialCoefficient
598-
(size_t coefficientSize = 128, Exp = sizediff_t)
599-
(ulong n, uint k)
600-
if (coefficientSize % (size_t.sizeof * 8) == 0 && coefficientSize >= (size_t.sizeof * 8))
601-
in (k <= n)
602-
{
603-
import mir.bignum.fp: Fp;
604-
605-
alias R = Fp!(coefficientSize, Exp);
600+
import mir.bignum.fp: Fp;
606601

607-
// TODO: For DivisionType == void
608-
// use full precision division for void when Fp division is ready
609-
static if (is(DivisionType == void))
610-
alias T = real;
611-
else
612-
alias T = DivisionType;
613-
614-
if (k > n - k)
615-
k = cast(uint)(n - k);
616-
617-
auto a = factorial!(coefficientSize, Exp)(k, n - k + 1);
618-
auto b = factorial!(coefficientSize, Exp)(k);
619-
auto exponent = a.exponent - b.exponent;
620-
a.exponent = b.exponent = -coefficientSize;
621-
auto ret = R(cast(T) a / cast(T) b);
622-
ret.exponent += exponent;
623-
return ret;
624-
}
602+
alias R = Fp!(coefficientSize, Exp);
603+
604+
if (k > n - k)
605+
k = cast(uint)(n - k);
606+
607+
auto a = factorial!(coefficientSize, Exp)(k, n - k + 1);
608+
auto b = factorial!(coefficientSize, Exp)(k);
609+
return a / b;
625610
}
626611

627612
///
@@ -632,7 +617,7 @@ unittest
632617
import mir.bignum.fp: Fp;
633618
import mir.math.common: approxEqual;
634619

635-
static assert(is(typeof(binomialCoefficient!double(30, 18)) == Fp!128), typeof(binomialCoefficient!double(30, 18)).stringof);
620+
static assert(is(typeof(binomialCoefficient(30, 18)) == Fp!128), typeof(binomialCoefficient(30, 18)).stringof);
636621
static assert(cast(double) binomialCoefficient(30, 18) == 86493225);
637622

638623
assert(approxEqual(cast(double) binomialCoefficient(100, 40), 1.374623414580281150126736972e+28));

0 commit comments

Comments
 (0)