русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Соглашения по исключениям


Дата добавления: 2015-06-12; просмотров: 500; Нарушение авторских прав


Необходимо предотвратить функцию от генерирования внутри нее исключительных ситуаций. Принимаются любые числовые значения, при этом только возможные исключения занимают стек числовых регистров.

Любое значение, посланное в числовой стек, проверяется на существование, тип (NaN или бесконечность) и состояние (денормальное, ноль, знак). Размер строки тестируется при минимальном и максимальном значении. Если вершина регистрового стека пуста или размер строки слишком мал, функция возвращает код ошибки.

Переполнение и отрицательное переполнение при очень больших или очень маленьких числах предотврашаются внутри функции.

Рисунок 20-6. Подпрограмма Перевода Чисел с Плавающей Точкой в ASCII Вид +-------------------------------------------------------------------------+| || || SOURCE || || +1 $title('Перевод числа с плавающей точкой в ASCII вид') || || || name floating_to_ascii || || public floating_to_ascii || extrn get_power_10:near, tos_status:near || ; || ; Эта подпрограмма переводит число с плавающей точкой || ; из вершины стека FPU в строку типа ASCII и отделяет || ; степень 10, масштабируя значение (в двоичном виде). || ; Максимальная длина строки символов регулируется || ; параметром, который должен быть больше 1. || ; Не-нормальные значения, денормальные значения и псевдо || ; -нули переводятся корректно. Однако, не-нормальные || ; величины и псевдо-нули более не поддерживаются || ; процессором i486 (в соответствии со стандартом IEEE) и || ; внутренне не генерируются. Возвращаемое значение || ; указывает сколько двоичных разрядов точности было || ; потеряно в не-нормальных или денормальных значениях. || ; Также указывается и величина мантиссы псевдо-нуля || ; (двоичным порядком). Целые числа меньшие 10**18 || ; переводятся точно, если принимающая строка ASCII || ; символов содержит достаточное количество позиций для || ; цифр этих чисел. В противном случае значение || ; переводиться в научную нотацию. || ; || ; В зависимости от результата подпрограмма выдает || ; следующие значения: || ; || ; 0 перевод выполнен, размер строки определен || ; 1 недопустимые аргументы || ; 2 точный целочисленный перевод, размер строки || ; определен || ; 3 неопределенность || ; 4 + NaN (не-число) || ; 5 - NaN || ; 6 + Бесконечность || ; 7 - Бесконечность || ; 8 встречен псевдо-ноль, размер строки определен || ; || ; Интерфейс для вызова из PLM-386/486 || ; || ; floating_to_ascii: || ; procedure (number, denormal_ptr, string_ptr, size_ptr, || ; field_size, power_ptr) word external; || ; declare (denormal_ptr, string_ptr, power_ptr, size_ptr) || ; pointer; || ; declare field_size word; || ; string_size based size_ptr word; || ; declare number real; || ; declare denormal integer based denormal_ptr; || ; || || ; declare power integer based power_ptr; || ; end floating_to_ascii; || ; || ; Величина с плавающей точкой должна быть на вершине || ; стека FPU. Эта подпрограмма требует три свободные || ; регистра в стеке и после отработки выталкивает || ; передаваемые значения из стека. Полученная строка || ; будет иметь начальный символ либо "+", либо "-", || ; указывая на знак величины. Затем следуют десятичные || ; цифры в ASCII виде. Числовое значение строки типа || ; ASCII будет равно (ASCII СТРОКА)*10**ПОРЯДОК. Если || ; данное число было нулем, то строка будет содержать || ; только знак и один символ 0. Величина размера строки || ; (string_size) указывает на полную длину строки символов, || ; включая символ знака. Строка (0) всегда будет || ; содержать знак. Возможно, что размер строки будет || ; меньше размера поля. Это бывает при нулях и целых || ; числах. Псевдо-ноль выдает особый код возврата. При || ; денормальных числах указывается степень двух || ; представленного значения. Степень десяти и строка будут || ; такими же, как если бы величина была бы простым нулем. || ; || ; Эта подпрограмма точно выдает десятичные целые до 18 || ; цифр. Целые величины имеют десятичный показатель || ; степени в строке из нулей. При нецелых величинах || ; точность результата заключена в двух последних || ; десятичных цифрах (двойная точность). Для || ; масштабирования величины в диапазоне, приемлемом для || ; данных типа BCD, используются команды возведения в || ; степень. Для перевода используется режим округления, || ; действующий при входе в подпрограмму. || ; || ; Следующие регистры не видны: || ; || ; eax ebx ecx edx esi edi eflags || ; || ; Определение стека. || ; || ebp_save equ dword ptr [ebp] || es_save equ ebp_save + size ebp_save || return_ptr equ es_save + size es_save || power_ptr equ return_ptr + size return_ptr || field_size equ power_ptr + size power_ptr || size_ptr equ field_size + size size_ptr || string_ptr equ size_ptr + size size_ptr || denormal_ptr equ string_ptr + size string_ptr || || parms_size equ size power_ptr + size field_size + || & size size_ptr + size string_ptr + || & size denormal_ptr || ; || ; Определение используемых констант. || ; || BCD_DIGITS equ 18 ; Количество цифр в величине типа BCD || WORD_SIZE equ 4 || BCD_SIZE equ 10 || MINUS equ 1 ; Определение выдаваемых значений || NAN equ 4 ; Выбраные здесь точные величины - || INFINITY equ 6 ; важны. Они должны соответствовать || INDEFINITE equ 3 ; возможным выдаваемым значениям и || PSEUDO_ZERO equ 8 ; тестироваться в том же порядке, как || INVALID equ -2 ; показано в этой программе. || ZERO equ -4 || DENORMAL equ -6 || UNNORMAL equ -8 || NORMAL equ 0 || EXACT equ 2 || ; || ; Определение положения временной области хранения. || ; || power_two equ word ptr [ebp - WORD_SIZE] || bcd_value equ tbyte ptr power_two - BCD_SIZE || bcd-byte equ byte ptr bcd_value || fraction equ bcd_value || || lokal_size equ size power_two + size bcd_value || ; || ; Выделить достаточный объем стека для || ; временных результатов. || ; || stack stackseg (lokal_size+6) ; Выделить пространство стека || ; для локальных данных. || +1 $eject || || code segment public er || extrn power_table:qword || ; || ; Константы, используемые этой функцией. || ; || even ; Оптимизировать до 16 цифр. || const10 dw 10 ; Подрегулировать значение для || ; ; слишком больших BCD. || ; || ; Перевести биты C3, C2, C1 и C0 в || ; значащие флаги и величины, используя || ; процедуру tos_status. || ; || status_table db UNNORMAL, NAN, UNNORMAL+MINUS, || & NAN+MINUS, NORMAL, INFINITY, || & NORMAL+MINUS, INFINITY+MINUS, || & ZERO, INVALID, ZERO+MINUS, INVALID, || & DENORMAL, INVALID, DENORMAL+MINUS, INVALID || floting_to_ascii proc || || call tos_status ; Посмотреть на состояние ST(0) || ; || ; Взять дескриптор из таблицы || ; || movzx eax, status_table[eax] || cmp al,INVALID ; ST(0) пуст? || jne not_empty || ; || ; ST(0) - пуст! Возвращает значение состояния. || ; || ret parms_size || ; || ; Удалить бесконечность из стека и выйти. || ; || found_infinity: || fstp st(0) ; Оставить fstp || jmp short exit_proc || ; || ; Длина строки слишком мала! || ; Выдает код недопустимости. || ; || small_string: || mov al,INVALID || exit_proc: || leave ; Восстановить стек || || pop es || ret parms_size || ; || ; В ST(0) находится NaN или || ; неопределенность. Сохранить значение || ; в памяти и просмотреть дробное поле || ; для того, чтобы отличить || ; неопределенность от обычного NaN. || ; || NAN_or_indefinite: || fstp fraction ; Для проверки - удалить значение || ; из стека. || test al,MINUS ; Посмотреть бит знака. || fwait ; Убедиться в выполнении сохранения. || jz exit_proc ; Если положительный знак, то не || ; может быть неопределенностью. || || mov ebx,0C0000000H ; Подавить верхние 32 разряда дробной || ; части. || || ; Сравнить разряды 63-32 || sub ebx,dword ptr fraction + 4 || || ; Разряды 31-0 должны быть нулями || or ebx,dword ptr fraction || jnz exit_proc || || ; Установить выдаваемое значение на || ; неопределенность || mov al,INDEFINITE || jmp exit_proc || ; || ; Выделить место в стеке для локальных переменных || ; и установить параметр адресации. || ; || not_empty: || push es ; Сохранить рабочий регистр || enter local_size,0 ; Установить адресацию стека || || ; Проверить, достаточно ли места в строке || mov ecx,field_size || cmp ecx,2 || jl small_string || || dec ecx ; Установить символ знака || || ; Посмотреть, может быть строка слишком большая для типа BCD || cmp ecx,BCD_DIGITS || jbe size_ok || || ; Иначе установить максимальный размер строки || mov ecx,BCD_DIGITS || size_ok: || cmp al,INFINITY ; Может быть бесконечность? || || ; Возвратить значение состояния для + или - бесконечности || jge found_infinity || || cmp al,NAN ; Можеть быть NaN или || jge NAN_or_indefinite ; неопределенность || || ; || ; Установить выдаваемое значение по умолчанию || ; и проверить, нормализовано ли число. || ; || fabs ; Использовать только положительные значения || ; || ; Бит знака в регистре AL содержит истинный знак величины. || ; || xor edx,edx ; Подготовить константу 0 || mov edi,denormal_ptr ; Обнулить счетчик денормальных чисел || mov [edi],dx || mov ebx,power_ptr ; Обнулить значение степени десяти || mov [ebx],dx || mov dl,al || and dl,1 || add dl,EXACT || cmp al,ZERO ; Проверить на ноль || jae convert_integer ; Перейти программу возведения в || ; степень, если значение равно нулю. || || fstp fraction || fwait || mov al,bcd_byte + 7 || or byte ptr bcd_byte +7,80h || fld fraction || fxtract || test al,80h || jnz normal_value || || fld1 || fsub || ftst || fstsw ax || sahf || jnz set_unnormal_count || ; || ; Найден псевдо-ноль || ; || fldlg2 ; Оценить степень десяти || add dl,PSEUDO_ZERO - EXACT || fmulp st(2),st || fxch ; Взять степеть десяти || fistp word ptr [ebx] ; Установить степень десяти || jmp convert_integer || || set_unnormal_count: || fxtract ; Взять исходную дробь, || ; и нормализовать. || fxch ; Взять счетчик не-нормальных чисел || fchs || fistp word ptr [edi] ; Установить счетчик || ; не-нормальных чисел || || ; || ; Вычислить десятичную величину вместе с этим числом || ; внутри одного порядка. || ; || ; Всегда при округлении будет присутствовать ошибка || ; из-за потери точности. В результате, мы || ; преднамеренно при вычислении порядка не стали || ; рассматривать LOG10 от значения дроби. Так как || ; дробь всегда больше или равна 1 и меньше двух, то || ; LOG10 от этой дроби не изменяет основной точности || ; функции. Для того, чтобы получить десятичный || ; порядок величины, надо просто умножить степень || ; двух на LOG10(2) и округлить результат с || ; отсечением до целого. || ; || normal_value: || fstp fraction ; Для дальнейшего использования || ; сохранить поле дроби. || fist power_twq ; Сохранить степень двух || fldlg2 ; Взять LOG10(2) || ; Теперь можно безопасно использовать || ; power_two || fmul ; Подготовить LOG10 от порядка числа || fistp word ptr [ebx] ; Здесь может быть применен любой || ; режим округления || ; || ; Проверить, чтобы величина числа || ; интерпретировалась как целое. || ; || ; CX имеет максимально позволенное количество десятичных цифр. || ; || fwait ; Ожидать допустимой степени десяти || ; || ; Возвести десять в степень величины значения || ; || movsx si,word ptr [ebx] || sub esi,ecx ; Подготовить в AX необходимый || ; коэффициент масштабирования. || ja adjust_result ; Перейти, если число не подходит || ; || ; Число между 1 и 10**(field_size - размер поля) || ; Проверить на целочисленность || ; || fild power_two ; Восстановить начальное значение || sub dl,NORMAL-EXACT ; Перевести в точное выдаваемое || ; значение || fld farction || fscale ; Подготовить полную величину, в этой || ; команде она не портится || fst st(1) ; Скопировать значение для сравнения || frndint ; Проверить на целочисленность || fcomp ; Сравнить значения || fstsw ax ; Сохранить состояние || sahf ; C3 = 1, значит это была целое число || || jnz convert_integer || || fstp st(0) ; Удалить нецелочисленное значение || add dl,NORMAL-EXACT ; Восстановить начальнное выдаваемое || ; значение || ; || ; Масштабировать число внутри диапазона, || ; позволенного форматом BCD. Операция || ; масштабирования выдает число внутри одного || ; десятичного порядка величины наибольшего || ; десятичного числа, представимого для данной длины || ; строки. || ; || ; Величина степени десяти для масштабирования || ; находится в регистре SI. || ; || adjust_result: || mov eax,esi ; Подготовить для возведения в || ; степень || mov word ptr [ebx],ax ; Установить начальную величину || ; степени десяти || neg eax ; Вычесть единицу для каждого порядка || ; величины, на который масштабируется || ; значение. || call get_power_10 ; Коэффициент масштабирования || ; представляется как порядок и дробь. || fld fraction ; Взять дробь || fmul ; Комбинировать дроби || mov esi,ecx ; Возвести десять в максимальную || ; степень || shl esi,3 ; Для того, чтобы значение BCD || ; входило в строку || fild power_two ; Комбинировать степень двух || faddp st(2),st || fscale ; Подготовить полное значение, || ; порядок остался не тронутым || fstp st(1) ; Удалить порядок || ; || ; Проверьте установленное значение по таблице || ; точных степеней десяти. Суммарные ошибки оценки || ; величины и степенной функции могут привести к || ; тому, что значение одного порядка величины будет || ; либо слишком маленькое, либо слишком большое для || ; поля типа BCD. Для устранения этой проблемы || ; протестируйте полученное значение - является ли || ; оно слишком большим или слишком маленьким. Затем || ; отрегулируйте его и значение степени десяти. || ; || test_power: || ; || ; Сравните с точной степенью. Используйте следующую || ; степень при уменьшении CX на единицу. || ; || fcom power_table[esi]+type power_table || fstsw ax ; Не надо ждать || sahf ; Если C3=C0=0, то слишком большое || jb test_for-small || fidiv const10 ; Иначе установить значение || and dl,not EXACT ; Удалить флаг того, что число точное || inc word ptr [ebx] ; Установить значение степени десяти || jmp short in_range ; Перевести значение в целое типа BCD || || test_for_small: || fcom power_table[esi] ; Проверить относительный размер || || fstsw ax ; Не ждать || sahf ; Если C0 = 0, то ST(0) больше или || ; равен нижшей границе || jc in_range ; Перевести значение в целое типа BCD || fimul const10 ; Подогнать значение под диапазон || dec word ptr [ebx] ; Подобрать значение степени десяти || in_range: || frndint ; Подготовить целое значение || ; || ; Утверждение: 0 <= TOS <= 999,999,999,999,999,999 || ; Число TOS будет точно представлено || ; 18-ю цифрами в формате BCD. || ; || convert_integer: || fbstp bcd_value ; Сохранить число в формате BCD || ; || ; При сохранении формата BCD установить регистры || ; для перевода в ASCII вид. || ; || mov esi,BCD_SIZE-2 ; Инициализировать значение || ; индекса BCD || mov cx,0f04h ; Установить счетчик сдвига и маску || mov ebx,1 ; Установить начальный размер ASCII || ; поля для знака || mov edi,string_ptr ; Взять адрес начала ASCII строки || mov ax,ds ; Скопировать DS в ES || mov es,ax || cld ; Установить режим автоматического || ; добавления единицы || mov al,'+' ; Очистить поле знака || test dl,MINUS ; Проверить на отрицательное значение || jz positive_result || || mov al,'-' || positive_result: || stosb ; Установить указатель строки на || ; последний знак || and dl,not MINUS ; Выключить бит знака || fwait ; Ожидать окончания команды fbstp || ; || ; Используемые регистры: || ; || ; AH: байт со значением типа BCD || ; AL: значение строки ASCII || ; DX: возвращаемое значение || ; CH: маска BCD = 0fh || ; CL: счетчик сдвига BCD = 4 || ; BX: ширина поля строки ASCII || ; ESI: индекс поля BCD || ; DI: указатель поля строки BCD || ; DS, ES: адрес сегмента строки ASCII || ; || ; Удалить начальные нули из числа. || ; || ; || skip_leading_zeroes: || mov ah,bcd_byte[esi] ; Взять байт BCD || mov al,ah ; Скопировать значение || shr al,cl ; Взять верхнюю по порядку цифру || and al,0fh ; Установить флаг нуля || jnz enter_odd ; Выйти из цикла, если в начале || ; обнаружены не нули || || mov al,ah ; Взять снова байт BCD || and al,0fh ; Взять нижнюю по порядку цифру || jnz enter-even ; Выйти из цикла, если обнаружены || ; ненулевые цифры || || dec esi ; Уменьшить индекс BCD || jns skip_leading_zeroes || ; || ; Вся мантисса состоит из нулей || ; || mov al,'0' ; Установить начальный ноль || stosb || inc ebx ; Увеличить длину строки || jmp short exit_with_value || ; || ; Теперь расширяем строку цифрами от || ; 0 до 9 по одной цифре на байт || ; || digit_loop: || mov ah,bcd_byte[esi] ; Взять байт BCD || mov al,ah || shr al,cl ; Взять верхнюю по порядку цифру || enter_odd: || add al,'0' ; Перевести в ASCII || stosb ; Занести цифру в строку ASCII || mov al,ah ; Взять нижнюю по порядку цифру || and al,0fh || inc ebx ; Увеличить счетчик размера поля || enter-even: || add al,'0' ; Перевести в ASCII || stosb ; Занести цифру в строку ASCII || inc ebx ; Увеличить счетчик размера поля || dec esi ; Перейти к следующему байту BCD || jns digit_loop || ; || ; Перевод закончен. Установить размер || ; строки и остаток || ; || exit_with_value: || mov edi,size_ptr || mov word ptr [edi],bx || mov eax,edx ; Установить выдаваемое значение || jmp exit_proc || || floating_to_ascii endp || code ends || end || || || +1 $title(Вычислить значение 10**AX) || || ; Эта подпрограмма вычисляет значение степени || ; 10**EAX. Точный результат выдается для значений в || ; диапазоне 0 <= EAX < 19. Все регистры прозрачны || ; и значение выдается в TOS как два числа: порядок || ; в ST(1) и дробь в ST(0). Величина порядка может || ; превышать наибольший порядок числа в расширенном || ; вещественном формате. В программе используются || ; три стековых регистра. || ; || name get_power_10 || public get_power_10, power_table || || stack stackseg 8 || || code segment public er || ; || ; Использовать точные значения от 1.0 до 1E18. || ; || even ; Оптимизировать 16-ти битовый доступ || power_table dq 1.0,1e1,1e2,1e3 || || dq 1e4,1e5,1e6,1e7 || || dq 1e8,1e9,1e10,1e11 || || dq 1e12,1e13,1e14,1e15 || || dq 1e16,1e17,1e18 || || get_power_10 proc || cmp eax,18 ; Проверить диапазон 0 <= AX < 19 || ja out_of_range || || fld power_table[eax*8] ; Взять точное значение || fxtract ; Отделить степень и || ; дробную часть || ret ; Оставить fxtract || ; || ; Вычислить значение, используя команду возведения || ; в степень. Используются следующие соотношения: || ; || ; 10**X = 2**(log2(10)*X) || ; 2**(I+F) = 2**I * 2**F || ; || ; Если ST(1) = I и ST(0) = 2**F, то команда fscale || ; выдает 2**(I+F). || ; || out_of_range: || || fldl2t ; TOS = LOG2(10) || enter 4,0 || || ; Сохранить значение степени десяти, P || ; || mov [ebp-4],eax || || ; TOS, X = LOG2(10)*P = LOG2(10**P) || ; || fimul dword ptr [ebp-4] || fld1 ; Установить TOS = -1.0 || fchs || fld st(1) ; Скопировать значение степени по || ; основанию два || frndint ; TOS = I; -бесконечность < I <= X, || ; где I - целое || ; Режим округления не имеет значения || fxch st(2) ; TOS = X, ST(1) = -1.0 || ; ST(2) = I || fsub st,st(2) ; TOS, F = X-I: || ; -1.0 < TOS <= 1.0 || || ; Восстановить начальный режим управления точностью || pop eax || f2xm1 ; TOS = 2**(F) - 1.0 || leave ; Восстановить стек || fsubr ; Подготовить 2**(F) || ret ; Оставить fsubr || || get_power_10 endp || || code ends || end || || +1 $title(Определение содержимого регистра TOS) || ; || ; Эта подпрограмма выдает значение от 0 до 15 в || ; регистр EAX в соответствии с содержанием вершины || ; стека FPU. Все регистры прозрачны, поэтому ошибки || ; исключены. Выдаваемое значение соответствует || ; битам C3, C2, C1 и C0 команды FXAM. || ; || name tos_status || public tos_status || || stack stackseg 6 || || code segment public er || || tos_status proc || fxam ; Взять состояние регистра TOS || fstsw ax ; Взять текущее состояние || mov al,ah ; Положить биты 10-8 в биты 2-0 || and eax,4007h ; Маскировать биты C3, C2, C1 и C0 || shr ah,3 ; Положить бит C3 в бит 11 || or al,ah ; Положить бит C3 в бит 3 || mov ah,0 ; Очистить возвращаемое значение || ret || || tos_status endp || || code ends || end || || |+-------------------------------------------------------------------------+


<== предыдущая лекция | следующая лекция ==>
Реакция на одновременные исключения | Специальные команды


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.371 сек.