Итак, чтобы умножить 976 на коэффициент 0,48576, следует сначала последний вручную умножить, например, на 216 = 65 536, и тем самым получить числитель соответствующей двоичной дроби (у которой знаменатель равен 65 536) — он будет равен 31834,76736, или, с округлением до целого 31 835. Такой точности хватит, если исходные числа не выходят, как у нас, за пределы трех-четырех десятичных разрядов. Теперь мы в контроллере должны умножить исходную величину 976 на константу 31 835 и полученное число 31 070 960 (оно оказывается 4-байтовым — S01DA1AF0, потому нашу Mui6i6 придется чуть модифицировать, как сказано при ее описании ранее) сдвигаем на 16 разрядов вправо:
;в ddHH: ddH: ddM: ddL число $01DA1AF0,
;его надо сдвинуть на 16 разрядов
сlrг cnt
div16L: ;деление на 65536
lsr ddHH ;сдвинули старший
ror ddH ;сдвинули 3-й
rоr ddM ;сдвинули 2-й
rоr ddL ;сдвинули младший
inc cnt
cpi cnt,16
brne divl6L ;сдвинули-поделили на 2 в 16
В результате, как вы можете легко проверить, старшие байты будут нулевыми, а в ddM:ddL окажется число 474 — тот же самый результат. Но и это еще не все, такая процедура приведена скорее для иллюстрации общего принципа. Ее можно еще больше упростить, если обратить внимание на то, что сдвиг на восемь разрядов есть просто перенос значения одного байта в соседний (в старший, если сдвиг влево, и в младший — если вправо). Итого получится, что для сдвига на 16 разрядов вправо нам надо всего-навсего отбросить два младших байта, и взять из исходного числа два старших ddHH:ddH — это и будет результат. Проверьте — S01DA и есть 474. Никаких других действий вообще не требуется!
Если степень знаменателя дроби, как в данном случае, кратна 8, то действительно никакого деления, даже в виде сдвига, не требуется, но чаще всего это не так. Однако и тут приведенный принцип может помочь: например, при делении на 215 (что может потребоваться, если, например, в нашем примере константа больше единицы) вместо пятнадцати кратного сдвига вправо результат можно сдвинуть на один разряд влево (фактически умножив число на два), а потом уже выделить из него старшие два байта. Итого процедура будет состоять из четырех операций сдвига и займет четыре такта. А в виде циклического сдвига на 15, как ранее, нам требуется в каждом цикле сделать четыре операции сдвига и одну увеличения счетчика: 15 х 5 = 75 простых однотактных операций, и еще 15 операций сравнения, из которых 14 займут два такта — итого 104 такта. А решение «в лоб» на основе операций целочисленного деления в несколько раз превышало бы и эту величину. Существенная разница, правда? Вот такая специальная арифметика в МК.
Это важная группа операций, ведь значительная часть устройств на основе МК предназначена для демонстрации чисел в том или ином виде. Это, естественно, можно делать только в десятичном формате, в то время как внутреннее представление чисел в регистрах двоичное. В некоторых микропроцессорных системах (в их число входит семейство