Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Отрицательные числа в МК
Самый простой метод представления отрицательных чисел — отвести один бит (логичнее всего — старший) для хранения знака. По причинам, которые вы поймете далее, значение 1 в этом бите означает знак "минус", а 0 — знак "плюс". Как будут выглядеть двоичные числа в таком представлении?
В области положительных чисел ничего не изменится, кроме того, что их диапазон сократится вдвое: например, для числа в байтовом представлении вместо диапазона 0..255 мы получим всего лишь 0..127 (0000 0000— 0111 1111). А отрицательные числа будут иметь тот же диапазон, только старший бит у них будет равен единице. Все просто, не правда ли?

Нет, неправда. Такое представление отрицательных чисел совершенно не соответствует обычной числовой оси, на которой влево от нуля идет минус единица, а затем числа по абсолютной величине увеличиваются. Здесь же мы получаем, во-первых, два разных нуля ("обычный" 0000 0000, и "отрицательный" 1000 0000), во-вторых, оси отрицательных и положительных чисел никак не стыкуются, и выполнение арифметических операций превратится в головоломку.

Поэтому поступим так: договоримся, что -1 соответствует число 255 (1111 1111), -2 — число 254 (1111 1110) и т. д., вниз до 128 (1000 0000), которое будет соответствовать -128 (и общий диапазон всех чисел получится от -128 до +127). Очевидно, что если вы в таком представлении хотите получить отрицательное число в обычном виде, то нужно из значения числа (например, 240) вычесть максимальное значение диапазона (255) и прибавить единицу (что равносильно вычитанию из 256). Если отбросить знак, то результат такого вычитания (16 в данном случае) называется еще дополнением до 2 (или просто дополнительным кодом) для исходного числа (а само исходное число 240 тогда будет дополнением до 2 для 16). Название "дополнение до 2" не зависит от разрядности числа, потому что верхней границей всегда служит степень двойки (в десятичной системе аналогичная операция называется "дополнение до 10").

Что произойдет в такой системе, если вычесть, например 2 из 1? Запишем это действие в двоичной системе обычным столбиком:
_00000001 00000010

В первом разряде результата мы без проблем получаем единицу, а уже для второго нам придется занимать единицу из старших, которые сплошь нули, поэтому представим себе, что у нас будто бы есть девятый разряд, равный единице, из которого заем в конечном итоге и происходит:
(1)00000001 - 00000010
11111111

На самом деле девятиразрядное число 1 0000 0000 есть не что иное, как 256, т. е. то же самое максимальное значение диапазона + единица, и мы здесь выполнили две операции: прибавили к уменьшаемому эти самые 256, а затем выполнили вычитание, но уже в положительной области для всех участвующих чисел. А что результат? Он будет равен 255, т. е. тому самому числу, которое, как мы договорились, представляет собой -1. То есть вычитание в такой системе происходит автоматически правильно, независимо от знака участвующих чисел.
Немного смущает только эта самая операция нахождения дополнения до 2, точнее, в данном случае до 256 — как ее осуществить на практике, если схема всего имеет 8 разрядов? В дальнейшем мы увидим, что на практике она не нужна: при вычитании и в микроконтроллерах, и в обычных электронных счетчиках все осуществляется автоматически.

Впрочем, в микропроцессорах есть и отдельная команда, которая возвращает дополнение до 2. В большинстве ассемблеров она называется neg, от слова "негативный", потому что просто-напросто меняет знак исходного числа, ес-'ли мы договариваемся считать числа "со знаком". Разберем из любопытства, как ее можно было бы осуществить "вручную", не обращаясь в действительности к девятому разряду. Для этого выпишем столбиком какое-нибудь число (далее для примера — 2 и 240), результаты операции нахождения его дополнения до 2, и результат еще одной манипуляции, которая представляет собой вычитание единицы из дополнения до 2, или, что то же самое, просто вычитания исходного числа из наивысшего числа диапазона (255):

Исходное число 2 00000010
Дополнение до 2 256 - 2 = 254 11111110
Дополнение до 1 255 - 2 = 253 11111101
Исходное число 240 11110000
Дополнение до 2 256-240= 16 00010000
Дополнение до 1 255-240= 15 00001111

Если мы сравним двоичные представления в верхней и нижней строках в каждом случае, то увидим, что их можно получить друг из друга инверсией каждого из битов. Эта операция называется нахождением обратного кода или дополнения до 1 (потому что число, из которого вычитается, содержит единицы во всех разрядах; для десятичной системы аналогичная операция называется "дополнение до 9"). Для нахождения дополнения до 1 девятый разряд не требуется, да и схему можно построить так, чтобы никаких вычитаний не производить, а просто переворачивать биты. Так и делается, конечно, но не ищите в микроконтроллерах специальной операции инверсии битов — для этого вызывается именно команда нахождения дополнения до 1 (в AVR-ассемблере она обозначается, как сот и определяется, как операция вычитания из $FF). Иначе говоря, для полного сведения вычитания к сложению нужно проделать три операции.

1. Найти дополнение до 1 для вычитаемого (инвертировать его биты).
2. Прибавить к результату 1, чтобы найти дополнительный код.
3. Сложить уменьшаемое и дополнительный код для вычитаемого.

Первые две операции и объединены в ассемблере в одну под именем neg, которая сразу возвращает дополнительный код 8-разрядного числа.

Для корректной работы с отрицательными числами в AVR есть специальные команды умножения (сложение и вычитание, вообще говоря, таких специальных команд не требуют), но в практические приемы работы с отрицательными числами мы здесь не будем углубляться. Дело в том, что с отрицательными числами (как и с дробными), иметь дело напрямую в 8-разрядных МК неудобно— их, например, приходится специальным образом преобразовывать при обмене с внешними устройствами, почти всегда имеющими свою разрядность и тем самым свое представление об отрицательных числах.
Так, в 8-разрядной системе число 255 есть минус единица, а в 16-разрядной минус единице соответствует число 65 535, в 32-разрядном— число 2 147 483 647 и т. п. В этих случаях число 255 будет интерпретировано как положительное 255, что приводит к излишней путанице. Так что лучше стараться "вогнать" числа в положительный диапазон, а знак "минус" (например, для температуры в градусах Цельсия) всегда можно учесть отдельно.



     
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru