Kontekst
Računanje fakultete. Gre za matematično funkcijo, ki je zmnožek vseh manjših števil, vključno z n -
(5! = 1 * 2 * 3 * 4 * 5 = 120). Funkcije za računanje fakultet sem napisal na več načinov – za primerjavo.
F#
Gre za funkcijski programski jezik s podporo objektnemu programiranju, ki temelji na .NET platformi. Primeren je za kompleksne algoritme, simulacije, analize, matematične izračune, paralelizacijo, podatkovno rudarjenje, umetno inteligenco...
Implementacija
Rekurzivno funkcijo za izračun fakultete sem dal v posebno knjižnico, da ni bilo krožne reference. To funkcijo kličemo potem iz F#. Uporabiti je potrebno BigInteger saj rezultati kmalu postanejo ogromni.
using System.Numerics; namespace FactorialLibrary { public struct RecursiveFactorial { public static BigInteger FactorialRecursive(BigInteger number) { return number > 1 ? number * FactorialRecursive(number - 1) : 1; } } }F# modul z rekurzivno, iterativno in eksotično funkcijo za izračun fakultete. Spodnja funkcija pa je klic funkcije iz zgoraj omenjene C# knjižnice.
module FactorialFSharpLibrary open FactorialLibrary let factorialExotic(n) = Seq.fold ( * ) 1I [1I .. n];; let rec factorialRecursive(n) = if n < 1I then 1I else n * factorialRecursive (n - 1I);; let factorialIterative(n:bigint) = let mutable result = 1I for i=1 to (int)n do result <- result * bigint(i) done result;; let factorialRecursiveCSharp(n) = RecursiveFactorial.FactorialRecursive(n);;V C# strukturi pa imamo iterativno in paralelno funkcijo za izračun fakultete. Prav tako pa kličemo tudi vse zgoraj napisane funkcije.
public struct Factorial { public static BigInteger Number { get; set; } public static BigInteger FactorialIterative() { var fact = new BigInteger(1); for (var i = 1; i <= Number; i++) { fact *= i; } return fact; } public static BigInteger FactorialIParallel() { var fact = new BigInteger(1); Parallel.For(1, (long)Number + 1, i => { fact *= i; }); return fact; } public static BigInteger FactorialFSharpExotic() { return FactorialFSharpLibrary.factorialExotic(Number); } public static BigInteger FactorialFSharpRecursive() { return FactorialFSharpLibrary.factorialRecursive(Number); } public static BigInteger FactorialFSharpIterative() { return FactorialFSharpLibrary.factorialIterative(Number); } public static BigInteger FactorialRecursiveOverFSharp() { return FactorialFSharpLibrary.factorialRecursiveCSharp(Number); } }V glavnem programu samo pokličemo vse metode in izpišemo rezultate. Čas izvajanja posamezne metode tudi izmerimo.
struct FactorialExamples { private const string Print = ":\n{0}"; public delegate BigInteger ExecuteMethod(); public static void MeasureMethod(string printLine, ExecuteMethod method) { var timer = Stopwatch.StartNew(); var result = method(); timer.Stop(); Console.WriteLine(string.Format(printLine + Print, result) + "\ntime: " + timer.ElapsedMilliseconds + "ms"); } public static void Main() { Factorial.Number = 100; Console.WriteLine("Factorial of {0}", Factorial.Number); MeasureMethod("recursive C# over F#", Factorial.FactorialRecursiveOverFSharp); MeasureMethod("iterative", Factorial.FactorialIterative); MeasureMethod("parallel", Factorial.FactorialIParallel); MeasureMethod("exotic F#", Factorial.FactorialFSharpExotic); MeasureMethod("recursive F#", Factorial.FactorialFSharpRecursive); MeasureMethod("iterative F#", Factorial.FactorialFSharpIterative); Console.ReadKey(); } }Rezultati fakultete števila 200 in čas izvajanja.
Testiranje
Vse funkcije tudi testiramo z Unit testi. Zgoraj so konstante za obvestila o napakah, spodaj pa klici vseh metod in primerjava njihovih rezultatov s pravilnim. Metode testiramo z različnimi argumenti.
[TestClass] public class TestFactorial { #region Printout fields private const string Recursive = "Error in recursive function"; private const string Iterative = "Error in iterative function"; private const string Parallel = "Error in parallel function"; private const string ExoticF = "Error in exotic F# function"; private const string IterativeF = "Error in iterative F# function"; private const string RecursiveF = "Error in recursive F# function"; #endregion private static void MethodRun(BigInteger parameter, BigInteger expectedResult) { Factorial.Number = parameter; var actual = Factorial.FactorialRecursiveOverFSharp(); Assert.AreEqual(expectedResult, actual, Recursive); actual = Factorial.FactorialIterative(); Assert.AreEqual(expectedResult, actual, Iterative); actual = Factorial.FactorialIParallel(); Assert.AreEqual(expectedResult, actual, Parallel); actual = Factorial.FactorialFSharpExotic(); Assert.AreEqual(expectedResult, actual, ExoticF); actual = Factorial.FactorialFSharpIterative(); Assert.AreEqual(expectedResult, actual, IterativeF); actual = Factorial.FactorialFSharpRecursive(); Assert.AreEqual(expectedResult, actual, RecursiveF); } #region Test Methods [TestMethod] public void TestFactorialsFor0() { MethodRun(0, 1); } [TestMethod] public void TestFactorialsFor1() { MethodRun(1, 1); } [TestMethod] public void TestFactorialsFor10() { MethodRun(10, 3628800); } [TestMethod] public void TestFactorialsFor20() { MethodRun(20, 2432902008176640000); } #endregion } }Rezultati testa - vsi testi so uspešni.
Za konec pa še metrika kode za C# projekte v tej rešitvi.
Ni komentarjev:
Objavite komentar