From 722db75dd0209626051e6e96461a41b31a94306b Mon Sep 17 00:00:00 2001 From: Artem-Darius Weber Date: Thu, 17 Apr 2025 16:08:53 +0300 Subject: [PATCH] =?UTF-8?q?(lab=205)=20feat:=20task-14:=20=D0=9F=D1=80?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=D1=81=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B?= =?UTF-8?q?=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B2=D1=8B=D1=87=D0=B8=D1=81=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D1=87=D0=B8=D1=81=D0=BB=D0=B0=20=D0=AD=D0=B9=D0=BB?= =?UTF-8?q?=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 16 ++- compose.yaml | 9 ++ lab 5/EulerFunction/EulerFunction.fsproj | 13 ++ lab 5/EulerFunction/Program.fs | 162 +++++++++++++++++++++++ 4 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 lab 5/EulerFunction/EulerFunction.fsproj create mode 100644 lab 5/EulerFunction/Program.fs diff --git a/Makefile b/Makefile index 08a856f..763cfb4 100644 --- a/Makefile +++ b/Makefile @@ -44,11 +44,15 @@ run-lab5-favorite-lang-fp: run-lab5-mutually-prime: dotnet run --project "lab 5/MutuallyPrimeTraversal/MutuallyPrimeTraversal.fsproj" +run-lab5-euler-function: + dotnet run --project "lab 5/EulerFunction/EulerFunction.fsproj" + # Запуск Lab 5 run-all-lab5: run-lab5-hello-world run-lab5-quadratic-equation run-lab5-circle-cylinder \ run-lab5-number-operations run-lab5-recursion-types run-lab5-function-factory \ run-lab5-number-traversal run-lab5-lambda-traversal run-lab5-conditional-traversal \ - run-lab5-number-examples run-lab5-favorite-lang run-lab5-favorite-lang-fp run-lab5-mutually-prime + run-lab5-number-examples run-lab5-favorite-lang run-lab5-favorite-lang-fp run-lab5-mutually-prime \ + run-lab5-euler-function help: @echo "Доступные команды:" @@ -76,6 +80,7 @@ help: @echo " make run-lab5-favorite-lang - Запустить программу о любимом языке программирования" @echo " make run-lab5-favorite-lang-fp - Запустить программу о любимом языке с суперпозицией и каррированием" @echo " make run-lab5-mutually-prime - Запустить программу обхода взаимно простых компонентов числа" + @echo " make run-lab5-euler-function - Запустить программу вычисления функции Эйлера" clean: dotnet clean @@ -91,13 +96,15 @@ lab5-docker-build: docker compose build lab5-hello-world lab5-quadratic-equation lab5-circle-and-cylinder \ lab5-number-operations lab5-recursion-types lab5-function-factory \ lab5-number-traversal lab5-lambda-traversal lab5-conditional-traversal \ - lab5-number-examples lab5-favorite-lang lab5-favorite-lang-fp lab5-mutually-prime + lab5-number-examples lab5-favorite-lang lab5-favorite-lang-fp lab5-mutually-prime \ + lab5-euler-function lab5-docker-run: docker compose up lab5-hello-world lab5-quadratic-equation lab5-circle-and-cylinder \ lab5-number-operations lab5-recursion-types lab5-function-factory \ lab5-number-traversal lab5-lambda-traversal lab5-conditional-traversal \ - lab5-number-examples lab5-favorite-lang lab5-favorite-lang-fp lab5-mutually-prime + lab5-number-examples lab5-favorite-lang lab5-favorite-lang-fp lab5-mutually-prime \ + lab5-euler-function # Docker lab 5 отдельные программы lab5-hello-world-docker-run: @@ -139,6 +146,9 @@ lab5-favorite-lang-fp-docker-run: lab5-mutually-prime-docker-run: docker compose up lab5-mutually-prime +lab5-euler-function-docker-run: + docker compose up lab5-euler-function + ci-local: circleci config validate circleci local execute diff --git a/compose.yaml b/compose.yaml index 3f9d165..0747068 100644 --- a/compose.yaml +++ b/compose.yaml @@ -125,4 +125,13 @@ services: volumes: - ./lab 5/MutuallyPrimeTraversal:/app stdin_open: true + tty: true + + lab5-euler-function: + build: + context: ./lab 5/EulerFunction + dockerfile: ../../Individual Task 1/Dockerfile + volumes: + - ./lab 5/EulerFunction:/app + stdin_open: true tty: true \ No newline at end of file diff --git a/lab 5/EulerFunction/EulerFunction.fsproj b/lab 5/EulerFunction/EulerFunction.fsproj new file mode 100644 index 0000000..fc052d3 --- /dev/null +++ b/lab 5/EulerFunction/EulerFunction.fsproj @@ -0,0 +1,13 @@ + + + + Exe + net7.0 + EulerFunction + + + + + + + \ No newline at end of file diff --git a/lab 5/EulerFunction/Program.fs b/lab 5/EulerFunction/Program.fs new file mode 100644 index 0000000..23dc711 --- /dev/null +++ b/lab 5/EulerFunction/Program.fs @@ -0,0 +1,162 @@ +open System + +let rec gcd a b = + if b = 0 then abs a + else gcd b (a % b) + +let areCoprime a b = + gcd a b = 1 + +let traverseCoprime (n: int) (operation: int -> int -> int) (initialValue: int) = + [1..n] + |> List.filter (fun i -> areCoprime n i) + |> List.fold operation initialValue + +let eulerFunction (n: int) = + let countOperation _ acc = acc + 1 + traverseCoprime n countOperation 0 + +let eulerFunctionFormula (n: int) = + let isPrime n = + if n <= 1 then false + elif n <= 3 then true + elif n % 2 = 0 || n % 3 = 0 then false + else + let sqrt_n = int (sqrt (float n)) + let rec checkDivisors i = + if i > sqrt_n then true + elif n % i = 0 || n % (i + 2) = 0 then false + else checkDivisors (i + 6) + checkDivisors 5 + + let rec getUniquePrimeFactors n divisor factors = + if n <= 1 then factors + elif n % divisor = 0 then + let newFactors = if List.contains divisor factors then factors else divisor :: factors + getUniquePrimeFactors (n / divisor) divisor newFactors + else + getUniquePrimeFactors n (divisor + 1) factors + + if n = 1 then 1 + else + let primeFactors = + if isPrime n then [n] + else + let factors = getUniquePrimeFactors n 2 [] + factors |> List.filter isPrime |> List.sort + + let result = + primeFactors + |> List.fold (fun acc p -> acc * (1.0 - 1.0 / float p)) (float n) + + int result + +let testTraverseCoprime () = + printfn "Тестирование функции traverseCoprime:" + + let testCases = [2; 5; 10; 12; 15; 20; 30] + + for n in testCases do + let coprimes = [1..n] |> List.filter (fun i -> areCoprime n i) + let sum = traverseCoprime n (fun a b -> a + b) 0 + let expectedSum = List.sum coprimes + + let product = traverseCoprime n (fun a b -> a * b) 1 + let expectedProduct = List.fold (fun acc x -> acc * x) 1 coprimes + + let count = traverseCoprime n (fun _ acc -> acc + 1) 0 + let expectedCount = List.length coprimes + + printfn "n = %d, взаимно простые числа: %A" n coprimes + + printfn " Сумма: %d (ожидаемая: %d) - %s" + sum expectedSum + (if sum = expectedSum then "OK" else "ОШИБКА") + + printfn " Произведение: %d (ожидаемое: %d) - %s" + product expectedProduct + (if product = expectedProduct then "OK" else "ОШИБКА") + + printfn " Количество: %d (ожидаемое: %d) - %s" + count expectedCount + (if count = expectedCount then "OK" else "ОШИБКА") + + printfn "" + +let testEulerFunction () = + printfn "Тестирование функции Эйлера (phi):" + + let expectedValues = [ + (1, 1); (2, 1); (3, 2); (4, 2); (5, 4); (6, 2); (7, 6); (8, 4); (9, 6); + (10, 4); (12, 4); (15, 8); (20, 8); (30, 8); (36, 12); (48, 16); (60, 16); (100, 40) + ] + + for (n, expected) in expectedValues do + let result = eulerFunction n + printfn " φ(%2d) = %2d (ожидаемое: %2d) - %s" + n result expected + (if result = expected then "OK" else "ОШИБКА") + + printfn "" + +let compareEulerFunctions () = + printfn "Сравнение двух способов вычисления функции Эйлера:" + + let testCases = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 12; 15; 20; 30; 36; 48; 60; 100] + + for n in testCases do + let result1 = eulerFunction n + let result2 = eulerFunctionFormula n + + printfn " n = %3d: φ(n) = %3d (через обход), φ(n) = %3d (по формуле) - %s" + n result1 result2 + (if result1 = result2 then "СОВПАДАЕТ" else "РАЗЛИЧАЕТСЯ") + + printfn "" + +[] +let main argv = + Console.OutputEncoding <- Text.Encoding.UTF8 + + printfn "Задание 14. Тестирование функции обхода взаимно простых чисел и вычисление функции Эйлера." + printfn "" + + testTraverseCoprime() + testEulerFunction() + compareEulerFunctions() + + printfn "Интерактивный режим:" + + let tryAgain = ref true + + while !tryAgain do + printf "Введите число для вычисления функции Эйлера (или 'q' для выхода): " + let input = Console.ReadLine() + + match input.ToLower() with + | "q" | "quit" | "exit" -> + tryAgain := false + | _ -> + match Int32.TryParse(input) with + | true, n when n > 0 -> + let startTime1 = DateTime.Now + let phi1 = eulerFunction n + let endTime1 = DateTime.Now + + let startTime2 = DateTime.Now + let phi2 = eulerFunctionFormula n + let endTime2 = DateTime.Now + + printfn " φ(%d) = %d" n phi1 + printfn " Через обход: %A" (endTime1 - startTime1) + printfn " По формуле: %A" (endTime2 - startTime2) + + if n <= 30 then + let coprimes = [1..n] |> List.filter (fun i -> areCoprime n i) + printfn " Взаимно простые числа с %d: %A" n coprimes + + printfn "" + | _ -> + printfn " Некорректный ввод. Пожалуйста, введите положительное целое число.\n" + + 0 \ No newline at end of file