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