model tiny
codeseg

    mov     ax, 0003h           ; установить текстовый режим
    int     10h                 ; 80x25x16

    mov     ax, 0E2Eh
    int     10h                 ; выдать на экран точку

    mov     ax, 8A7Ch
    mov     bx, 000Ah          ; основание 10-й системы (число 10)
    mov     cx, 0010h          ; 16 знаков после запятой

R:  mul     bx
    xchg    ax, dx              ; обменять AX и DX
    add     al, '0'             ; поправить цифру для нормального
                                ; ее отображения на экране
    mov     ah, 0Eh
    int     10h                 ; выдать цифру
    xchg    ax, dx
    loop    R                   ; повторить, пока CX не будет равен 0

    int     20h
Никогда не думал, что это будет настолько просто... Иногда при целочисленно-вещественных операциях получаются числа в регистрах, которые бы нужно распечатать. Дробное число в диапазоне от 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 раз. Ровно столько нужно, чтобы выдать все цифры до последнего бита. Все, вот такие вот непропечённые пироги :-)
4 мая, 2020
© 2007-2022 Получил права - води смело