Лабораторна робота №5

Обробка раціональних та комплексних чисел мовами функціонального програмування

Мета

Опанувати технологію абстракції даних в мовах функціонального програмування. Реалізувати програму обробки раціональних та комплексних чисел мовами функціонального програмування, представивши ці числа конструкціями типу «пара».

Виконав: студент групи ІПЗ-42
Лавріненко В.В.


Умова завдання

Варіант №14

14.1. Створити список з парною кількістю елементів, які є різними раціональними числами у вигляді дробив. Для кожної пари елементів списку виконати множення дробив, результат якого записати у новий список. Надрукувати список, утворений з результатів множення кожної пари.

14.2. Створити список з парною кількістю елементів, які є комплексними числами в алгебраїчній формі a + ib. Створити новий список, елементами якого є частки від ділення кожної пари комплексних чисел першого списку. Надрукувати новий список.


Обгрунтування вибору середовища та мови функціонального програмування

Для розв'язку завдання було обрано мову Scheme та середовище DrRacket. Основними критеріями, за якими було зроблено вибір, є:

  • Наявність доволі великої кількості довідникових джерел інформації з синтаксису та поведінки даної мови. Це, в свою чергу, забезпечено й тим, що дана мова є діалектом розповсюдженої мови - LISP.

  • Відносна простота даної мови у засвоєнні, а середовища - використані, завдяки зрозумілому мінімалістичному користувацьому інтерфейсу, що надає найпоширеніший функціонал для написання та відлагоджування коду.


Структура програми (НІРО - діаграма)


Код програми

Завдання 14.1
#lang racket
; Лавріненко В.В.
; ІПЗ-42
; Л.р. 5, завдання 14.1

; процедура для отримання значення у списку за індексом
(define (get-list-element elements n) 
  (if (= n 1) 
      (car elements)
         (get-list-element (cdr elements) (- n 1 ))
  )
)

; процедура для створеного модифікованого списка
(define (create-list n)
  ; допоки не дійшли до кінця списку, створювати поточний елемент як добуток двох вхідних
  (cond [(or (< n (/(length numbers) 2)) (= n (/(length numbers) 2)))
         (let ([first-fraction (get-list-element numbers (- (* 2 n) 1))]
           [second-fraction (get-list-element numbers (* 2 n))])
           ; результуючий список формується на основі щойно створеного елементу та списку, утвореного рекурсивиним викликом
           ; процедури для наступних елементів
           (append (list(cons (*(car first-fraction) (car second-fraction)) (*(cdr first-fraction) (cdr second-fraction))))
                   (create-list (+ n 1)))
          )
         ]
        ; у випадку, якщо вхідний список вичерпано, повернути порожній список
        [else
         '()]
  )
)

; процедура друкування списку
(define (print-fractions list n)
  (cond
    ; кожен некінцевий елемент друкувати як "a/b, "
    [(< n (length list))
        (begin
          (display (car (get-list-element list n)))
          (display "/")
          (display (cdr (get-list-element list n)))
          (display ", ")
          (print-fractions list (+ n 1))
        )
    ]
    ; кінцевий елемент друкувати як "a/b"
    [(= n (length list))
        (begin
          (display (car (get-list-element list n)))
          (display "/")
          (display (cdr (get-list-element list n)))
          (print-fractions list (+ n 1))
        )
    ]
    ; по закінченню списку надрукувати перехід на новий рядок
    [else
     (display "\n")
    ]
  )
)

(define numbers (list (cons 1 2) (cons 5 4) (cons 7 13) (cons 4 19)))
(display "The starting fractions list: ")
(print-fractions numbers 1)
(display "The new fractions list: ")
(print-fractions (create-list 1) 1)
					
Завдання 14.2
#lang racket
; Лавріненко В.В.
; ІПЗ-42
; Л.р. 5, завдання 14.2

; процедура отримання дійсної частини комплексного числа
(define (complex-number-real-part n) (car n))

; процедура отримання уявної частини комплексного числа
(define (complex-number-imaginary-part n) (cdr n))

; процедура отримання квадрату числа
(define (square x)
  (* x x))

; процедура отримання значення r при обчисленні полярного представлення комплексного числа
(define (get-r n)
  (* 1.0 (sqrt (+ (square (complex-number-real-part n)) (square (complex-number-imaginary-part n))))))

; процедура отримання значення кута при обчисленні полярного представлення комплексного числа
(define (get-phi n)
  (* 1.0 (atan (complex-number-imaginary-part n) (complex-number-real-part n))))


; процедура для отримання значення у списку за індексом
(define (get-list-element elements n) 
  (if (= n 1) 
      (car elements)
         (get-list-element (cdr elements) (- n 1 ))
  )
)

; процедура для створеного модифікованого списка
(define (create-list n)
  ; допоки не дійшли до кінця списку, створювати поточний елемент на основі двох вхідних
  (cond [(or (< n (/(length complex-numbers) 2)) (= n (/(length complex-numbers) 2)))
         (let* ([first-complex-number (get-list-element complex-numbers (- (* 2 n) 1))]
           [second-complex-number (get-list-element complex-numbers (* 2 n))]
           [a1 (car first-complex-number)]
           [b1 (cdr first-complex-number)]
           [a2 (car second-complex-number)]
           [b2 (cdr second-complex-number)]
           )
           ; поточний елемент обчислюється як:
           ; a = (a1*a2 + b1*b2) / (a2^2 + b2^2)
           ; b = -(a1*b2 - b1*a2) / (a2^2 + b2^2)
           (append (list(cons  (/ (+ (* a1 a2) (* b1 b2)) (+ (* a2 a2) (* b2 b2)))
                               (* -1 (/ (- (* a1 b2) (* b1 a2)) (+ (* a2 a2) (* b2 b2))))))
                   ; результуючий список формується на основі щойно створеного елементу та списку, утвореного рекурсивиним викликом
                   ; процедури для наступних елементів
                   (create-list (+ n 1)))
          )
         ]
        ; у випадку, якщо вхідний список вичерпано, повернути порожній список
        [else
         '()]
  )
)

; процедура друкування списку
(define (print-complex list n)
  (cond
    ; кожен некінцевий елемент друкувати як "( [-]a +- b i ), "
    [(< n (length list))
        (begin
          (display "(")
          (if (< (car (get-list-element list n)) 0)
              (display " - ")
              (display " ")
          )
          (display (abs (car (get-list-element list n))))
          (if (< (cdr (get-list-element list n)) 0)
              (display " - ")
              (display " + ")
          )
          (display (abs (cdr (get-list-element list n))))
          (display "i ), ")
          (print-complex list (+ n 1))
        )
    ]
    ; кінцевий елемент друкувати як "( [-]a +- b i )"
    [(= n (length list))
        (begin
          (display "(")
           (if (< (car (get-list-element list n)) 0)
              (display " - ")
              (display " ")
          )
          (display (abs (car (get-list-element list n))))
          (if (< (cdr (get-list-element list n)) 0)
              (display " - ")
              (display " + ")
          )
          (display (abs (cdr (get-list-element list n))))
          (display "i )")
          (print-complex list (+ n 1))
        )
    ]
    ; по закінченню списку надрукувати перехід на новий рядок
   [else
    (display "\n")
   ]
  )
)

; процедура друкування списку у полярному представленні
(define (print-complex-polar list n)
  (cond
    [(< n (length list))
        (begin
          (display "(")
          (display (~r (get-r (get-list-element list n)) #:precision 4))
          (display " * ( cos(")
          (display (~r (get-phi (get-list-element list n)) #:precision 4))
          (display ") + i * sin(")
          (display (~r (get-phi (get-list-element list n)) #:precision 4))
          (display ") ), ")
          (print-complex-polar list (+ n 1))
        )
    ]
    [(= n (length list))
        (begin
          (display "(")
          (display (~r (get-r (get-list-element list n)) #:precision 4))
          (display " * ( cos(")
          (display (~r (get-phi (get-list-element list n)) #:precision 4))
          (display ") + i * sin(")
          (display (~r (get-phi (get-list-element list n)) #:precision 4))
          (display ") )")
          (print-complex-polar list (+ n 1))
        )
    ]
    ; по закінченню списку надрукувати перехід на новий рядок
   [else
    (display "\n")
   ]
  )
)


(define complex-numbers (list (cons 7 -4) (cons 3 2) (cons 10 -3) (cons -4 7) (cons -19 5) (cons 10 1)))
(display "The starting complex numbers list: ")
(print-complex complex-numbers 1)
(display "The new complex numbers list: ")
(print-complex (create-list 1) 1)
(display "The new complex numbers list, printed in polar form: ")
(print-complex-polar (create-list 1) 1)
					


Скріншоти результатів


Оцінка достовірності результатів

  • Завдання 14.1 Правильність формування початкового списку було перевірено для списку: (1/2, 5/4, 7/13, 4/19, -5/27, 8/19). Так, внаслідок ручних обчислень, було виявлено, що очікуваний список повинен мати вигляд: (1 * 5 / 2 * 4 = 5 / 8, 7 * 4 / 13 * 19 = 28 / 247, -5 * 8 / 27 * 19 = -40 / 513). Отриманий насправді результат: (5/8, 28/247, -40/513), - збігається з очікуваним.

  • Завдання 14.2 Правильність виконання програми було перевірено для послідовності виразів: ( 7 - 4i ), ( 3 + 2i ), ( 10 - 3i ), ( - 4 + 7i ), ( - 19 + 5i ), ( 10 + 1i ). Так, за допомогою ресурсу https://formula.co.ua/uk/content/complex-numbers.html було виявлено чисельні результати для кожної з пар:(1−2i), (−0.9384615384615385−0.8923076923076924i), (−1.8316831683168318+0.6831683168316832i). В дійсності ж було отримано результат: ( 1 - 2i ), ( - 61/65 - 58/65i ), ( - 185/101 + 69/101i ). Внаслідок окремого обчислення значень отриманих дробових чисел у формі десяткових дробів за допомогою онлайн-калькулятора, виявилось, що отримані значення збігаються з очікуваними.

  • Правильність виконання виведення комплексних чисел у полярному зображенні було перевірено за допомогою онлайн-кулькулятора Worfram|Alpha. Так, для значення 1 - 2i було отримано наближене значення 2.2361(cos(-1.1071)+isin(-1.1071)), що збігається з результатом, отриманим програмою.


Висновки

В лабораторній роботі було реалізовано обидва завдання, що передбачають маніпуляції зі списками пар, що мають втілювати, відповідно, дробові та комплексні числа.

При програмній реалізації завдання 14.1 труднощів не постало: умова є цілком зрозумілою, тож виконання було доволі елементарним.

Труднощі виникли при розв'язанні завдання 14.2. Так, спершу виникла необхідність більш детального дослідження теоретичних матеріалів з метою знаходження формули ділення комплексних чисел, що легко можна перевести в код. Також, внаслідок виведення результату ділення цілих чисел у дробовому форматі, виникла проблема ручної перевірки відповідності значення даних дробів очікуваним десятковим дробам, що також зайняло певний час.