|
|
|
@ -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 ""
|
|
|
|
|
|
|
|
|
|
[<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
|