Фантазии о Вселенной и мой личный сайт
Страница запроса

Печать дробной части числа

model tiny
codeseg
    
    mov     ax, 0x0003          ; установить текстовый режим
    int     0x10                ; 80x25x16
    
    mov     ax, 0x0E2E
    int     0x10                ; выдать на экран точку
    
    mov     ax, 0x8A7C
    mov     bx, 0x000A          ; основание 10-й системы (число 10)
    mov     cx, 0x0010          ; 16 знаков после запятой
    
R:  mul     bx
    xchg    ax, dx              ; обменять AX и DX
    add     al, '0'             ; поправить цифру для нормального
                                ; ее отображения на экране
    mov     ah, 0x0E
    int     0x10                ; выдать цифру
    xchg    ax, dx
    loop    R                   ; повторить, пока CX не будет равен 0

    int     0x20
Никогда не думал, что это будет настолько просто... Иногда при целочисленно-вещественных операциях получаются числа в регистрах, которые бы нужно распечатать. Дробное число в диапазоне от 0 до 1 в 16-ти разрядном регистре будет теперь в диапазоне от 0 до 65535. Как несложно заметить, дробные числа просто увеличивают масштаб, вот и все, переходя якобы в целые числа. Чем больше разрядность того или иного регистра, тем точнее будет дробь. Так, при 32-й разрядности диапазон будет составлять от 0 до 4294967296, а 64-х разрядной будет достигать даже до 18446744073709551616. Соответственно увеличивается точность.

Так, допустим, есть в распоряжении 8 разрядов. Следовательно, числа в диапазоне от 0 до 255, соответственно дробь от 0 до 1. При увеличении на 1 дробь будет увеличится на 1/256 ~ 0,004. Точность где-то до второго знака. В 16-ти разрядном регистре уже будет до 1/65536 ~ 0,00002 точность до 4-го знака, максимум, до 5, но там уже будет не попадать нечетное количество раз... ладно, это уже другой разговор :-) В общем, и т.д. Конечно, насчет чисел с плавающей точкой будет точность достигаться неимоверная, но принцип остается тот же, в любом случае, ограничение разрядов существует.

Переход в десятичную систему производиться крайне просто. Данное число умножается на 10. Все что перенеслось в верхний разряд, будет первой цифрой в [-1] разряде. Число как бы "подвинется" влево... Лучше представить это математически. Любую десятичную дробь Q (=0..1) можно представить в виде:

f1*10-1 + f2*10-2 + .... + fn*10-n = Q

Теперь возьмем Y = 65536*Q, и оно должно быть целым, без дробной части. Тогда Y тоже можно представить как последовательность из разрядов, но уже в другом виде. Так как у нас Y будет шестнадцатеричным и в диапазоне от 0 до 65535, зная, что всего есть 4 разряда, то:

k0*160 + k1*161 + k2*162 + k3*163 = Y (1)

Теперь умножим оба уравнения на 10.
Первое превратится в:

f1 + [f2*10-1 + .... + fn+1*10-n-1]дробь = 10*Q (2)

Соответственно G = 10*Y тоже, отчего (1) переформируется в иное представление:

[k0*160 + k1*161 + k2*162 + k3*163] + k4*164 = G (3)

где k0 ... k4 будут уже другими числами... но это неважно. Здесь появляется новый разряд, 4-й, который не вмещается в 16-ти разрядный регистр [его владения выделены квадратными скобками]. Причем интересная вещь получается - k всегда меньше или равно 10. Почему? Как помним, Y = Q*65536, значит G = 10*Y = 10*(Q*65536). Теперь, разделив обе части уравнения (3) на 65536 и отбрасывая полученную дробную часть, получим: k4 = 10*Q, где Q есть число в пределах от 0 до 1. Следовательно, k4 не может быть больше 10. Помня о том, что это число, которое мы получили, есть старший разряд, записываемый в DX, нужно сказать о том, что 10*Q = f1 (если отбросить дробную часть) из уравнения (2). Так что f1 = k4 А что такое 10*Q? Это обычное смещение запятой вправо:

0,484821 * 10 =
4,848210 * 10 =
48,48210 * 10 = .... и т.д.

Так что при последовательных умножениях регистра AX на 10 можно последовательно получить цифры из десятичной дроби, что и требовалось доказать. Хотя... это доказательство мало чего стоит, если его сравнить с Настоящими Математическими Доказательствами.

Думаю, дальше сложностей не будет. После того, как в регистре DL было получено значение k4, регистры AX и DX обмениваются. Так как на экран нельзя выдавать числа от 0 до 9, они не будут хорошо выглядеть... потому что в таблице ASCII, если вывести на экран символ номер 1, выдасться "мордочка", а не эта самая единица @_@ Символы цифр начинаются c 48 номера в таблице ASCII. Т.е. нужно полученное значение цифры прибавить к 48: ADD AL, 0x30. Используя BIOS-прерывание вывода символа на экран в режиме телетайпа (код AH=0x0E), программа печатает цифру на экран. Снова происходит обмен регистрами и это действие повторяется 16 раз. Ровно столько нужно, чтобы выдать все цифры до последнего бита. Все, вот такие вот непропеченые пироги :-)