Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Pol_Grem_-_ANSI_Common_Lisp_High_tech_-_2012.pdf
Скачиваний:
28
Добавлен:
12.03.2016
Размер:
4.85 Mб
Скачать

9

Числа

«Перемалывание чисел» (решение числовых задач большого объема) – одна­ из сильных­ сторон­ Лиспа­. В нем имеет­ся­ бога­тый­ набор­ число­вых­ типов,­ а по их поддерж­­ке он даст фору­ многим­ другим­ язы­кам.

9.1. Типы

Common Lisp предос­тав­ля­ет­ множе­ст­во­ различ­ных­ число­вых­ типов:­ це­ лые чис­ла, числа­ с плаваю­щей­ запя­той,­ рацио­наль­ные­ и комплекс­ные­ числа­. Большин­ст­во­ функций,­ рассмот­рен­ных­ в этой главе,­ рабо­та­ют­ одина­ко­во­ со всеми­ типа­ми­ чисел,­ за исклю­че­ни­ем,­ может­ быть, ком­ плексных­ чисел,­ к кото­рым­ неко­то­рые­ из этих функций­ не приме­ни­мы­.

Целое­ число­ запи­сы­ва­ет­ся­ строкой­ цифр: 2001. Число­ с плаваю­щей­ за­ пятой,­ поми­мо­ цифр, содер­жит­ деся­тич­ный­ разде­ли­тель ­– точку,­ на­ пример­ 253.72, или 2.5372e2 в экспо­нен­ци­аль­ном­ представ­ле­нии­. Рацио­­ нальная­ дробь представ­ля­ет­ся­ в виде­ отно­ше­ния­ двух целых­ чисел:­ 2/3. Комплекс­ное­ число­ вида­ a+bi мож­но запи­сать­ как #c(a b), где a и b – два дейст­ви­тель­ных­ числа­ одно­го­ типа­.

Провер­ку­ на принад­леж­­ность к соот­вет­ст­вую­ще­му­ типу­ осуще­ст­в­ля­ют­ преди­ка­ты­ integerp, floatp и complexp. Иерар­хия­ числен­­ных типов­ пред­ ставле­на­ на рис. 9.1.

Ниже­ приве­де­ны­ основ­ные­ прави­ла,­ соглас­но­ кото­рым­ мож­но опре­де­­ лить, число­ како­го­ типа­ будет­ полу­че­но­ в резуль­та­те­ вычис­ле­ния:­

1.Если­ функция­ прини­ма­ет­ хотя­ бы одно­ число­ с плаваю­щей­ запя­­ той, она также­ вернет­ деся­тич­ную­ дробь (или комплекс­ное­ число,­ компо­нен­ты­ кото­ро­го ­– деся­тич­ные­ дроби)­ . Так (+ 1.0 2) вернет­ 3.0, а (+ #c(0 1.0) 2) вернет­ #c(2.0 1.0).

2.Рацио­наль­ная­ дробь при возмож­но­сти­ будет­ сокра­ще­на­ до цело­го­ числа­. Вызов­ (/ 10 2) вернет­ 5.

9.2. Преобразование и извлечение

155

3.Комплекс­ные­ числа,­ мнимая­ часть кото­рых­ равна­ нулю,­ будут­ преоб­­ ра­зова­ны­ в дейст­ви­тель­ные­. Таким­ обра­­зом, вызов­ (+ #c(1 -1) #c(2 1)) вернет­ 3.

Прави­ла­ 2 и 3 вступа­ют­ в силу­ в момент­ считы­ва­ния­ выра­же­ния,­ по­ этому:­

> (list (ratiop 2/2) (complexp #c(1 0))) (NIL NIL)

ratio

rational bignum integer

fixnum bit

real

 

short float

 

 

number

float

single float

double float

 

 

 

 

long float

complex

 

 

 

 

 

Рис. 9.1. Числен­ные­ типы­

 

 

9.2.Преобразование и извлечение

ВЛиспе­ имеют­ся­ средст­ва­ для преоб­ра­зо­ва­ния,­ а также­ извле­че­ния­ компо­нен­тов­ чисел,­ принад­ле­жа­щих­ любым­ типам­. Функция­ float пре­ обра­зу­ет­ любое­ дейст­ви­тель­ное­ число­ в экви­ва­лент­ную­ ему деся­тич­ную­ дробь:

> (mapcar #’float ’(1 2/3 .5)) (1.0 0.66666667 0.5)

Также­ можно­ конвер­ти­ро­вать­ любое­ число­ в целое,­ но к этому­ преоб­ра­зо­­ ванию­ не всегда­ следу­ет­ прибе­гать,­ посколь­ку­ это может­ повлечь­ за со­ бой неко­то­рую­ поте­рю­ инфор­ма­ции­. Цело­чис­лен­ную­ компо­нен­ту­ любо­­ го дейст­ви­тель­но­го­ числа­ можно­ полу­чить­ с помо­щью­ функции­ truncate­:

> (truncate 1.3) 1 0.2999995

Второе­ значе­ние­ явля­ет­ся­ резуль­та­том­ вычи­та­ния­ перво­го­ значе­ния­ из аргу­мен­та­. (Разни­ца­ в .00000005 возни­ка­ет­ вследст­вие­ неиз­беж­ной­ неод­­ нознач­но­сти­ опера­ций­ с плаваю­щей­ запя­той­.)

Функции­ floor, ceiling и round также­ приво­дят­ свои аргу­мен­ты­ к цело­­ числен­­ным значе­ни­ям­. С помо­щью­ floor, возвра­щаю­щей­ наиболь­шее­ целое­ число,­ меньшее­ или равное­ задан­но­му­ аргу­мен­ту,­ а также­ ceiling, возвра­щаю­щей­ наимень­шее­ целое,­ большее­ или равное­ аргу­мен­ту,­ мы

156

Глава 9. Числа

можем­ обобщить­ функцию­ mirror? (стр. 62) для распо­зна­ва­ния­ палин­д­­ ромов:

(defun palindrome? (x)

(let ((mid (/ (length x) 2))) (equal (subseq x 0 (floor mid))

(reverse (subseq x (ceiling mid))))))

Как и truncate, функции­ floor и ceiling вторым­ значе­ни­ем­ возвра­ща­ют­ разни­цу­ между­ аргу­мен­том­ и своим­ первым­ значе­ни­ем:­

> (floor 1.5) 1 0.5

В действительности, мы могли­ бы опре­де­лить­ truncate таким­ обра­зом:­

(defun our-truncate (n) (if (> n 0)

(floor n) (ceiling n)))

Для полу­че­ния­ ближай­ше­го­ к аргу­мен­ту­ цело­го­ числа­ суще­ст­ву­ет­ функ­ ция round. В случае­ когда­ ее аргу­мент­ равно­уда­лен­ от обоих­ целых­ чи­ сел, Common Lisp, как и многие­ другие­ язы­ки, не округ­ля­ет­ его, а воз­ враща­ет­ ближай­шее­ четное­ число:­

> (mapcar #’round ’(-2.5 -1.5 1.5 2.5)) (-2 -2 2 2)

Такой­ подход­ позво­ля­ет­ сгладить­ нако­п­ле­ние­ ошибок­ округ­ле­ния­ в ря­ де прило­же­ний­. Одна­ко­ если­ необ­хо­ди­мо­ округ­ле­ние­ вверх, мож­но на­ писать­ такую­ функцию­ само­стоя­тель­но­.1 Как и осталь­ные­ функции­ та­ кого­ рода,­ round в каче­ст­ве­ второ­го­ значе­ния­ возвра­ща­ет­ разни­цу­ меж­ ду исход­ным­ и округ­лен­­ным числа­ми­.

Функция­ mod возвра­ща­ет­ второе­ значе­ние­ анало­гич­но­го­ вызо­ва­ floor, а функция­ rem – второе­ значе­ние­ вызо­ва­ truncate. Мы уже исполь­зо­ва­ли­ функцию­ mod (стр. 107) для опре­де­ле­ния­ дели­мо­сти­ двух чисел­ и для на­ хожде­ния­ пози­ции­ элемен­та­ в кольце­вом­ буфе­ре­ (стр. 137).

Для дейст­ви­тель­ных­ чисел­ суще­ст­ву­ет­ функция­ signum, кото­рая­ воз­ вратит­ 1, 0 или -1 в зави­си­мо­сти­ от того,­ каков­ знак аргу­мен­та:­ плюс, ноль или минус­. Модуль­ числа­ можно­ полу­чить­ с помо­щью­ функции­ abs. Таким­ обра­зом,­ (* (abs x) (signum x)) = x.

> (mapcar #’signum ’(-2 -0.0 0.0 0 .5 3)) (-1 -0.0 0.0 0 1.0 1)

В неко­то­рых­ реали­за­ци­ях­ -0.0 может­ суще­ст­во­вать­ сам по себе,­ как в приме­ре,­ приве­ден­ном­ выше­. В любом­ случае­ это не игра­ет­ роли,­ и в вычис­ле­ни­ях­ -0.0 ведет­ себя­ в точно­сти­ как 0.0.

1Функция­ format при округ­ле­нии­ не гаран­ти­ру­ет­ даже­ того,­ будет­ ли полу­че­­ но четное­ или нечет­ное­ число­. См. стр. 136.

9.3. Сравнение

157

Рацио­наль­ные­ дроби­ и комплекс­ные­ числа­ явля­ют­ся­ структу­ра­ми,­ со­ стоящи­ми­ из двух частей­. Полу­чить­ соот­вет­ст­вую­щие­ цело­чис­лен­­ные компо­нен­ты­ рацио­наль­ной­ дроби­ мож­но с помо­щью­ функций­ numerator и denominator. (Если­ аргу­мент­ уже явля­ет­ся­ целым­ числом,­ то первая­ функция­ вернет­ сам аргу­мент,­ а послед­няя ­– едини­цу­.) Анало­гич­но­ функции­ realpart и imagpart извле­ка­ют­ дейст­ви­тель­ную­ и мнимую­ час­ ти комплекс­но­го­ числа­. (Если­ аргу­мент­ не комплекс­ный,­ то первая­ вер­ нет это число,­ а вторая ­– ноль.)

Функция­ random прини­ма­ет­ целые­ числа­ или деся­тич­ные­ дроби­. Выра­­ жение­ вида­ (random n) вернет­ число,­ большее­ или равное­ нулю­ и мень­ шее n, и это значе­ние­ будет­ того­ же ти­па, что и аргу­мент­.

9.3. Сравнение

Для сравне­ния­ двух чисел­ мож­но приме­нять­ преди­кат­ =. Он возвра­ща­­ ет исти­ну,­ если­ аргу­мен­ты­ числен­­но экви­ва­лент­ны,­ то есть их разность­ равна­ нулю:­

>(= 1 1.0)

T

>(eql 1 1.0) NIL

Он менее­ строг, чем eql, так как послед­ний­ также­ требу­ет,­ чтобы­ его ар­ гумен­ты­ были­ одно­го­ типа­.

Преди­ка­ты­ для сравне­ния:­ < (меньше),­ <= (меньше­ или равно),­ = (равно),­ >= (больше­ или равно),­ > (больше)­ и /= (не равно)­ . Все они при­нима­ют­ один или более­ аргу­мен­тов­. Вызван­ные­ с одним­ аргу­мен­том,­ они всегда­ возвра­ща­ют­ исти­ну­. Для всех функций,­ кроме­ /=, вызов­ с тремя­ и более­ аргу­мен­та­ми:­

(<= w x y z)

равно­це­нен­ объеди­не­нию­ попар­ных­ сравне­ний:­

(and (<= w x) (<= x y) (<= y z))

Так как /= возвра­ща­ет­ исти­ну,­ лишь когда­ ни один из аргу­мен­тов­ не ра­ вен друго­му,­ выра­же­ние:­

(/ w x y z)

экви­ва­лент­но­

(and (/= w x) (/= w y) (/= w z) (/= x y) (/= x z) (/= y z))

Суще­ст­ву­ют­ также­ специа­ли­зи­ро­ван­ные­ преди­ка­ты­ zerop, plusp и minusp, прини­маю­щие­ только­ один аргу­мент­ и возвра­щаю­щие­ исти­ну,­ если­ он =, > или < нуля­ соот­вет­ст­вен­­но. Эти преди­ка­ты­ взаимо­ис­клю­чаю­щие­. Что каса­ет­ся­ -0.0 (если­ реали­за­ция­ его исполь­зу­ет),­ то, несмот­ря­ на знак минус,­ это число­ = 0

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]