C#で総乗を求める

とてつもない数学

 総乗を求めたかったので作った。

総乗とは

ja.wikipedia.org
 総和が全部の値を足し算するように、総乗は全部の値を掛け算する。
要はそれだけ。

例えば1から10までの総乗をPI(1,5)と表現する。
この場合、実際の計算は次のようになる。

PI(1,5) = 1×2×3×4×5 = 120

他にも、PI(5,12)だとこのようになる。

PI(5,12) = 5×6×7×8×9×10×11×12 = 19958400

さらに数列を突っ込んで総乗を求める場合もある。

できたもの

class MyMath
{
    /// <summary>
    /// 総乗
    /// </summary>
    /// <typeparam name="T">総乗に使う値の型</typeparam>
    /// <param name="start">開始する値</param>
    /// <param name="limit">上限値(含む)</param>
    /// <returns>startからlimitの総乗</returns>
    public T Product<T>(T start, T limit) where T : IComparable
    {
        if (start.CompareTo(limit) > 0) Swap<T>(ref start, ref limit);

        var p = start;
        for (var v = (dynamic)start + 1; v <= limit; v++) p *= v;

        return p;
    }

    /// <summary>
    /// 総乗(答えが大きくなりそうならこっち)
    /// </summary>
    /// <typeparam name="T">総乗に使う値の型</typeparam>
    /// <typeparam name="U">戻り値の型</typeparam>
    /// <param name="start">開始する値</param>
    /// <param name="limit">上限値(含む)</param>
    /// <returns>startからlimitの総乗</returns>
    public U Product<T, U>(T start, T limit)
    where T : IComparable
    {
        if (start.CompareTo(limit) > 0) Swap<T>(ref start, ref limit);

        var p = default(U);
        p = (dynamic)start;
        for (var v = (dynamic)start + 1; v <= limit; v++) p *= v;

        return p;
    }

    /// <summary>
    /// 総乗
    /// </summary>
    /// <typeparam name="T">引数の型</typeparam>
    /// <param name="nums">総乗する値の配列</param>
    /// <returns>配列内の総乗</returns>
    public T Product<T>(T[] nums)
    {
        return nums.Aggregate((result, current) => result * (dynamic?)current);
    }

    /// <summary>
    /// 総乗(大きくなりそうな場合)
    /// </summary>
    /// <typeparam name="T">引数の型</typeparam>
    /// <typeparam name="U">戻り値の型</typeparam>
    /// <param name="nums">総乗する値の配列</param>
    /// <returns>配列内の総乗</returns>
    public U Product<T, U>(T[] nums)
    {
        var e = default(U);
        e = (dynamic)1;
        foreach (var n in nums) e = e * (dynamic?)n;

        return e;
    }

    public void Swap<T>(ref T a, ref T b)
    {
        var tmp = a;
        a = b;
        b = tmp;
    }
}

実行結果1

var m = new MyMath();
Console.WriteLine($"PI(1, 100) = {m.Product<int, BigInteger>(1,100)}");
PI(1, 100) = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

実行結果2

var m = new MyMath();
int[] a = new int[] { 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25 };
Console.WriteLine($"PI(a) = {m.Product<int, BigInteger>(a)}");
PI(a) = 2635284526875

実行結果3

var m = new MyMath();
decimal[] a = new decimal[] { 1.1M, 2.2M, 3.3M, 4.4M, 5.5M, 6.6M, 7.7M, 8.8M, 9.9M };
Console.WriteLine($"PI(a) = {m.Product<decimal, decimal>(a)}");
PI(a) = 855652.058110080

整数型の制約がない

 なんでジェネリックの制約にIIntegerNumberみたいなのないんですか…
zenn.dev
ほんまこのブログの通りになって困惑した。
無理矢理Dynamicつけて通したけど。
自分しか使わんからまぁええやろ