You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
5.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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 ""
[<EntryPoint>]
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