C#で分数を扱うクラスライブラリ

#C#で分数を扱うクラスライブラリ
##ダウンロード
https://drive.google.com/drive/folders/1eZ07-CQSnDO570tjqnGdzbzYf7BW5CnX?usp=sharing

##ソースコード

```cs:FractionLib.cs
namespace FractionLib {
    public static class Fraction {
        /// <summary>
        ///     Which is it larger number.
        /// </summary>
        /// <param name="s">(string)Integer or fraction</param>
        /// <param name="t">(string)Integer or fraction</param>
        public static string Compare(string s, string t) {
            int numerator_s = 0;
            int numerator_t = 0;
            int denominator_s = 0;
            int denominator_t = 0;

            if (s.Contains("/")) {
                numerator_s = int.Parse(s.Split('/')[0]);
                denominator_s = int.Parse(s.Split('/')[1]);
            } else {
                numerator_s = int.Parse(s);
                denominator_s = 1;
            }

            if (t.Contains("/")) {
                numerator_t = int.Parse(t.Split('/')[0]);
                denominator_t = int.Parse(t.Split('/')[1]);
            } else {
                numerator_t = int.Parse(t);
                denominator_t = 1;
            }

            string result;

            if (((float)numerator_s / denominator_s) >= ((float)numerator_t / denominator_t)) {
                result = $"{numerator_s}/{denominator_s}";
            } else {
                result = $"{numerator_t}/{denominator_t}";
            }



            return result;
        }

        /// <summary>
        ///     Add number to number.
        /// </summary>
        /// <param name="s">(string)Integer or fraction</param>
        /// <param name="t">(string)Integer or fraction</param>
        public static string Add(string s, string t) {
            int numerator_s = 0;
            int numerator_t = 0;
            int denominator_s = 0;
            int denominator_t = 0;
            if (s.Contains("/")) {
                numerator_s = int.Parse(s.Split('/')[0]);
                denominator_s = int.Parse(s.Split('/')[1]);
            } else {
                numerator_s = int.Parse(s);
                denominator_s = 1;
            }

            if (t.Contains("/")) {
                numerator_t = int.Parse(t.Split('/')[0]);
                denominator_t = int.Parse(t.Split('/')[1]);
            } else {
                numerator_t = int.Parse(t);
                denominator_t = 1;
            }

            int lcm = CalcLcm.Lcm(denominator_s, denominator_t);
            string result = $"{(numerator_s * (lcm / denominator_s)) + (numerator_t * (lcm / denominator_t))}/{lcm}";

            return (result);
        }

        /// <summary>
        ///     Multiply number to number.
        /// </summary>
        /// <param name="s">(string)Integer or fraction</param>
        /// <param name="t">(string)Integer or fraction</param>
        public static string Times(string s, string t) {
            int numerator_s = 0;
            int numerator_t = 0;
            int denominator_s = 0;
            int denominator_t = 0;
            if (s.Contains("/")) {
                numerator_s = int.Parse(s.Split('/')[0]);
                denominator_s = int.Parse(s.Split('/')[1]);
            } else {
                numerator_s = int.Parse(s);
                denominator_s = 1;
            }

            if (t.Contains("/")) {
                numerator_t = int.Parse(t.Split('/')[0]);
                denominator_t = int.Parse(t.Split('/')[1]);
            } else {
                numerator_t = int.Parse(t);
                denominator_t = 1;
            }
            string result = $"{numerator_s * numerator_t}/{(denominator_s * denominator_t)}";
            return (result);
        }

        /// <summary>
        ///     Invert numeric and denominator.
        /// </summary>
        /// <param name="s">(string)Integer or fraction</param>
        public static string Invert(string s) {
            int numerator = 0;
            int denominator = 0;
            if (s.Contains("/")) {
                numerator = int.Parse(s.Split('/')[0]);
                denominator = int.Parse(s.Split('/')[1]);
            } else {
                numerator = int.Parse(s);
                denominator = 1;
            }

            string result = $"{denominator}/{numerator}";

            if(numerator == 0) {
                result = "None.";
            }
            return (result);
        }

        /// <summary>
        ///     Shape to irreducible fraction.
        /// </summary>
        /// <param name="s">(string)Integer or fraction</param>
        public static string Shape(string s) {
            int numerator = 0;
            int denominator = 0;
            if (s.Contains("/")) {
                numerator = int.Parse(s.Split('/')[0]);
                denominator = int.Parse(s.Split('/')[1]);
            } else {
                numerator = int.Parse(s);
                denominator = 1;
            }

            int gcd = CalcGcd.Gcd(numerator, denominator);
            numerator /= gcd;
            denominator /= gcd;

            string result;

            if (denominator < 0) {
                numerator *= -1;
                denominator *= -1;
            }

            if (denominator == 1) {
                result = numerator.ToString();
            } else {
                result = $"{numerator}/{denominator}";
            }

            return result;
        }

        /// <summary>
        ///     Convert to fraction.
        /// </summary>
        /// <param name="n">(int)Numerator</param>
        /// <param name="d">(int)Denominator</param>
        public static string ToFraction(int n, int d) {
            if(d == 0) {
                return "Zero divided";
            }
            string result = $"{n}/{d}";
            return result;
        }
    }

    public static class CalcGcd {
        /// <summary>
        ///     Calculate greatest common divisor.
        /// </summary>
        /// <param name="i">(int)number</param>
        public static int Gcd(int i, int j) {
            if (i < j) {
                Gcd(j, i);
            }

            while (j != 0) {
                int surplus = i % j;
                i = j;
                j = surplus;
            }

            return i;
        }
    }

    /// <summary>
    ///     Calculate least common multiple.
    /// </summary>
    /// <param name="i">(int)number</param>
    public static class CalcLcm {
        public static int Lcm(int i, int j) {
            int gcd = CalcGcd.Gcd(i, j);
            return i * j / gcd;
        }
    }
}
```

##使用例

```sample.cs
using System;
using FractionLib;

public class Compare {
    public static void Main() {
        Random r = new Random();
        int num = 3;
        int randomNum = 10;
        int[] numerator_a = new int[num];
        int[] denominator_a = new int[num];
        int[] numerator_b = new int[num];
        int[] denominator_b = new int[num];

        for(int i = 0; i < num; i++) {
            numerator_a[i] = r.Next(-randomNum, randomNum);
            denominator_a[i] = r.Next(-randomNum, randomNum);
            if(denominator_a[i] == 0) {
                denominator_a[i]++;
            }
            numerator_b[i] = r.Next(-randomNum, randomNum);
            denominator_b[i] = r.Next(-randomNum, randomNum);
            if (denominator_b[i] == 0) {
                denominator_b[i]++;
            }
        }

        string[] fraction_a = new string[num];
        string[] fraction_b = new string[num];

        Console.WriteLine("Compare");

        for (int i = 0; i < num; i++) {
            fraction_a[i] = Fraction.ToFraction(numerator_a[i], denominator_a[i]);
            fraction_b[i] = Fraction.ToFraction(numerator_b[i], denominator_b[i]);
        }

        for(int i = 0; i < num; i++) {
            Console.WriteLine($"Which is larger number {fraction_a[i]} or {fraction_b[i]}.");
            Console.WriteLine($"result : {Fraction.Compare(fraction_a[i], fraction_b[i])}");
        }

        Console.WriteLine();
        Console.WriteLine("Add");

        for (int i = 0; i < num; i++) {
            Console.WriteLine($"Add {fraction_a[i]} to {fraction_b[i]}.");
            Console.WriteLine($"result : {Fraction.Add(fraction_a[i], fraction_b[i])}");
        }

        Console.WriteLine();
        Console.WriteLine("Multiply");

        for (int i = 0; i < num; i++) {
            Console.WriteLine($"Multiply {fraction_a[i]} to {fraction_b[i]}.");
            Console.WriteLine($"result : {Fraction.Times(fraction_a[i], fraction_b[i])}");
        }

        Console.WriteLine();
        Console.WriteLine("Invert");

        for (int i = 0; i < num; i++) {
            Console.WriteLine($"Invert {fraction_a[i]}.");
            Console.WriteLine($"result : {Fraction.Invert(fraction_a[i])}");
        }

        Console.WriteLine();
        Console.WriteLine("Shape");

        for (int i = 0; i < num; i++) {
            Console.WriteLine($"Shape {fraction_a[i]} to irreducible fraction.");
            Console.WriteLine($"result : {Fraction.Shape(fraction_a[i])}");
        }
    }
}
```

##実行結果

```
Compare
Which is larger number 3/1 or -9/-8.
result : 3/1
Which is larger number 8/4 or 3/9.
result : 8/4
Which is larger number -6/7 or 4/6.
result : 4/6

Add
Add 3/1 to -9/-8.
result : -33/-8
Add 8/4 to 3/9.
result : 84/36
Add -6/7 to 4/6.
result : -8/42

Multiply
Multiply 3/1 to -9/-8.
result : -27/-8
Multiply 8/4 to 3/9.
result : 24/36
Multiply -6/7 to 4/6.
result : -24/42

Invert
Invert 3/1.
result : 1/3
Invert 8/4.
result : 4/8
Invert -6/7.
result : 7/-6

Shape
Shape 3/1 to irreducible fraction.
result : 3
Shape 8/4 to irreducible fraction.
result : 2
Shape -6/7 to irreducible fraction.
result : -6/7
```

##機能
###Compare
　このメソッドでは大小の比較を行い、大きい方を出力として返します。同値である場合は前者を返します。

```cs
/// <summary>
///     Which is it larger number.
/// </summary>
/// <param name="s">(string)Integer or fraction</param>
/// <param name="t">(string)Integer or fraction</param>
public static string Compare(string s, string t) {
    int numerator_s = 0;
    int numerator_t = 0;
    int denominator_s = 0;
    int denominator_t = 0;

    if (s.Contains("/")) {
        numerator_s = int.Parse(s.Split('/')[0]);
        denominator_s = int.Parse(s.Split('/')[1]);
    } else {
        numerator_s = int.Parse(s);
        denominator_s = 1;
    }

    if (t.Contains("/")) {
        numerator_t = int.Parse(t.Split('/')[0]);
        denominator_t = int.Parse(t.Split('/')[1]);
    } else {
        numerator_t = int.Parse(t);
        denominator_t = 1;
    }

    string result;

    if (((float)numerator_s / denominator_s) >= ((float)numerator_t / denominator_t)) {
        result = $"{numerator_s}/{denominator_s}";
    } else {
        result = $"{numerator_t}/{denominator_t}";
    }

    return result;
}
```

###Add
　このメソッドでは加算を行い、その計算結果を出力として返します。

```cs
/// <summary>
///     Add number to number.
/// </summary>
/// <param name="s">(string)Integer or fraction</param>
/// <param name="t">(string)Integer or fraction</param>
public static string Add(string s, string t) {
    int numerator_s = 0;
    int numerator_t = 0;
    int denominator_s = 0;
    int denominator_t = 0;
    if (s.Contains("/")) {
        numerator_s = int.Parse(s.Split('/')[0]);
        denominator_s = int.Parse(s.Split('/')[1]);
    } else {
        numerator_s = int.Parse(s);
        denominator_s = 1;
    }

    if (t.Contains("/")) {
        numerator_t = int.Parse(t.Split('/')[0]);
        denominator_t = int.Parse(t.Split('/')[1]);
    } else {
        numerator_t = int.Parse(t);
        denominator_t = 1;
    }

    int lcm = CalcLcm.Lcm(denominator_s, denominator_t);
    string result = $"{(numerator_s * (lcm / denominator_s)) + (numerator_t * (lcm / denominator_t))}/{lcm}";

    return (result);
}
```

###Times
　このメソッドでは乗算を行い、その計算結果を出力として返します。

```cs
/// <summary>
///     Multiply number to number.
/// </summary>
/// <param name="s">(string)Integer or fraction</param>
/// <param name="t">(string)Integer or fraction</param>
public static string Times(string s, string t) {
    int numerator_s = 0;
    int numerator_t = 0;
    int denominator_s = 0;
    int denominator_t = 0;
    if (s.Contains("/")) {
        numerator_s = int.Parse(s.Split('/')[0]);
        denominator_s = int.Parse(s.Split('/')[1]);
    } else {
        numerator_s = int.Parse(s);
        denominator_s = 1;
    }

    if (t.Contains("/")) {
        numerator_t = int.Parse(t.Split('/')[0]);
        denominator_t = int.Parse(t.Split('/')[1]);
    } else {
        numerator_t = int.Parse(t);
        denominator_t = 1;
    }
    string result = $"{numerator_s * numerator_t}/{(denominator_s * denominator_t)}";
    return (result);
}
```

###Invert
　このメソッドでは逆数を求めます。

```cs
/// <summary>
///     Invert numeric and denominator.
/// </summary>
/// <param name="s">(string)Integer or fraction</param>
public static string Invert(string s) {
    int numerator = 0;
    int denominator = 0;
    if (s.Contains("/")) {
        numerator = int.Parse(s.Split('/')[0]);
        denominator = int.Parse(s.Split('/')[1]);
    } else {
        numerator = int.Parse(s);
        denominator = 1;
    }

    string result = $"{denominator}/{numerator}";

    if(numerator == 0) {
        result = "None.";
    }
    return (result);
}
```

###Shape
　このメソッドでは分数を既約分数、または整数に変形します。

```cs
/// <summary>
///     Shape to irreducible fraction.
/// </summary>
/// <param name="s">(string)Integer or fraction</param>
public static string Shape(string s) {
    int numerator = 0;
    int denominator = 0;
    if (s.Contains("/")) {
        numerator = int.Parse(s.Split('/')[0]);
        denominator = int.Parse(s.Split('/')[1]);
    } else {
        numerator = int.Parse(s);
        denominator = 1;
    }

    int gcd = CalcGcd.Gcd(numerator, denominator);
    numerator /= gcd;
    denominator /= gcd;

    string result;

    if (denominator < 0) {
        numerator *= -1;
        denominator *= -1;
    }

    if (denominator == 1) {
        result = numerator.ToString();
    } else {
        result = $"{numerator}/{denominator}";
    }

    return result;
}
```

###ToFraction
　このメソッドでは2つの整数値から分数を生成します。2つの引数のうち前者が分子、後者が分母になります。

```cs
/// <summary>
///     Convert to fraction.
/// </summary>
/// <param name="n">(int)Numerator</param>
/// <param name="d">(int)Denominator</param>
public static string ToFraction(int n, int d) {
    if(d == 0) {
        return "Zero divided";
    }
    string result = $"{n}/{d}";
    return result;
}
```

###その他
　その他の機能として、`Fraction`クラス以外に`CalcLcm`クラス、`CalcGcd`クラスを用いて最小公倍数や最大公約数を求めることも可能です。

##あとがき
　分数を扱う外部クラスとしてインスタンスを生成して分数計算を用いることも考えましたが、コードの一部で分数の計算を行いたいときにわざわざインスタンスを生成して計算するのも面倒だったので分数の文字列をそのまま扱えるようにしました。
　C#では演算子をオーバーロードして分数に拡張もできるので、今後実数全体を演算子等含めて自由に扱えるクラスライブラリの作成も面白そうだなと思ってます。