Например задача Сделать функцию которая бы число с плавающей запятой (в ассемблере с точкой) представила бы её значение в четырёх байтах (то есть с одинарной точностью) если целое число не ноль например (1.5) или (-123.456) то это делается без проблем это число нужно сформировать в 32 битах 1 - бит знак числа 8 - бит экспонента 23 - бита мантиса где первый бит будет знаком числа то есть если первый бит сделать (0) то число положительное (1.5) а если первый бит сделать (1) то число отрицательное (-1.5) в следующие 8 бит нужно вписать значение экспоненты это тоже сделать не трудно если целое число 1 то в этих 8 битах прописываем число 127 если от 2 до 4 то 128 если от 4 до 8 то 129 если от 8 до 16 то 130 если от 16 до 32 то 131 если от 32 до 64 то 132 ............... ............... ............... если от 4194304 до 8 388 608 то 149 думаю логика для експоненты где целое число не ноль понятна в 23 бита мантисы вписываем целую часть плюс дробную (если она есть) для мантисы это конечно сильно утрированное объяснение но я думаю тот кто поможет мне ответить на мой последующий вопрос хорошо знает как нужно формировать эти 23 бита в мантисе Ещё раз повторюсь если целое число не ноль то всё делается без проблем А вот если целое число ноль например 0.1 0.01 0.123 0.1234567 то здесь формирование экспоненты и мантисы совершенно не понятно Если кто в теме подскажите пожалуйста как формировать экспоненту и мантису если целое число ноль В интернете я так и не нашёл ответ на этот вопрос там только описывается как это сделать если целое число не ноль то есть расклад который я утрированно описал выше
[math]0,1234567=(-1)^{s}\cdot 2^{p-b}\cdot 1,m[/math] где [math]S[/math] ― знаковый бит, [math]p[/math] ― порядок, [math]b[/math] ― смещение порядка для данного формата, [math]m[/math] ― дробная часть. Формат в который требуется перевести ― 32 бита. Тогда мантисса 23 бита и [math]b=127[/math]. [math]S[/math] можно найти сразу: [math]S=0[/math]. Чтобы найти [math]p[/math] требуется найти логарифм от 0,1234567 по основанию 2. Это можно сделать через MSoft Excell =LOG(число; основание). [math]log_{2}(0,1234567)=-3,01792[/math] округляем "вниз" до [math]-4[/math] [math]p-b=-4[/math] [math]p=123_{10}=7B_{16}=01111011_{2}[/math] [math]0,1234567=\frac{x}{2^{23}}\cdot 2^{-4}=\frac{x}{2^{27}}=\frac{x}{8388608}[/math] [math]x=0,1234567\cdot 8388608=1035629,8612736[/math]~[math] 1035630_{10}={\color{red}1}11111001101011011011110_{2}[/math] [math]0,1234567=S.{\color{red}p}.m=0.{\color{red}{01111011}}.11111001101011011011110_{2}=[/math] [math]=0{\color{red}{011.1101.1}}111.1100.1101.0110.1101.1110_{2}=3D.FC.D6.DE_{16}[/math]
Спасибо Mikl___ Извиняюсь, вопрос не теме В макросах masm32 можно делать арифметические действия, в частности деление, а вот какая нибудь фишка для определения остатка есть ? Ещё раз прошу прощения Mikl___ за вопрос не по теме
assch, а причём здесь макросы? общий случай операциятип (в битах)делимоеделительчастноеостатокнельзя делить на AAM imm 8 на 8 в регистре AL непосредственное число imm от 1 до 255 в регистре АH в регистре АL0 div/idiv16 на 8в регистре АХв 8-битном регистре или 8-битной ячейке памятив регистре АLв регистре АH0 и АН32 на 16в паре регистров DX:AX в 16-битном регистре или 16-битной ячейке памятив регистре АXв регистре DX0 и DX64 на 32в паре регистров EDX:EAX в 32-битном регистре или 32-битной ячейке памятив регистре EАXв регистре EDX0 и EDX 128 на 64 в паре регистров RDX:RAX в 64-битном регистре или 64-битной ячейке памяти в регистре RАX в регистре RDX0 и RDX частный случай: если делимое [math]Y[/math], а делитель [math]X=2^{N}[/math] тогда частное [math]=Y\;SHR,N[/math] а остаток [math]=Y\;AND,(N-1)[/math]
Просто хочу сделать одну макрофункцию которая бы под капотом произвела бы определённую арифметику (не оставляя следов в основном байт-коде) то есть как вы понимаете без участия регистров и команд процессора и вернула бы интересующее меня значение что то типа mov eax , @asd(параметры макроса) По этому я и спрашиваю (фигурально выражаясь) есть ли такой инструмент в макросах в котором при делении можно узнать остаток
assch, я не экстрасенс и по обрывкам сообщения не могу догадаться чего от меня хотят, но если требуется деление и получение остатка без команд целочисленного деления, то можно использовать: получение результата по таблице заменить деление на многократное вычитание сдвиги и вычитание умножение и сдвиги использовать FPU, SSE, SSE2 и т.д.
Всё оказалось гораздо проще Нашёл статью про макросы http://www.allasm.ru/comp_06.php и там нашёл оператор - MOD Возвращает остаток от деления операнда op1 на операнд op2 res = op1 MOD op2 Всем большое спасибо за подсказки
С помощью ваших подсказок за которые вам большое спасибо "Век живи век учись" сделал макрофункцию для своей платформы на которой я работаю - masm32 она переводит текстовое представление числа с плавающей точкой одинарной точности в текстовое десятичное число Если кому интересно выкладываю макрофункцию Большому тест-драйву я её не подвергал но вроде бы работает Если кто увидит ошибки поделитесь пожалуйста Пилотное название макрофункции незатейлевое - @NumberReal4 (число Real4) Код (ASM): @NumberReal4 MACRO p1:REQ local znak,buf,var,temp,mant,flag,exp,dop ;--------------------------------- IF @InStr(1,<p1>,<->) EQ 0 znak CATSTR <0> ELSE znak CATSTR <1> ENDIF ;--------------------------------- buf CATSTR <> FORC var,<p1> IF @InStr(1,< -+>,<var>) EQ 0 buf CATSTR buf,<var> ENDIF ENDM ;--------------------------------- temp CATSTR %@InStr(1,<%buf>,<.>) ;--------------------------------- mant CATSTR %@SubStr(<%buf>,1,temp-1) ;--------------------------------- IF @SizeStr(<%mant>) GT 9 .ERR <Real4 - many symbol in integer> ENDIF ;--------------------------------- buf CATSTR @SubStr(<%buf>,temp+1) ;--------------------------------- IF @SizeStr(<%buf>) GT 9 .ERR <Real4 - many symbol in fractional part> ENDIF ;--------------------------------- IF mant EQ 0 mant CATSTR <> var CATSTR <24> goto nxt1 ENDIF ;---------------------------- flag CATSTR <0> temp CATSTR <> :nxt2 temp CATSTR temp,%@CatStr(@CatStr(mant MOD 2)) mant CATSTR %@CatStr(mant/2) IF mant EQ 0 goto nxt3 ENDIF flag CATSTR %@CatStr(flag+1) goto nxt2 :nxt3 ;---------------------------- exp CATSTR %@CatStr(127+flag) ;---------------------------- IF flag GT 23 var CATSTR %@CatStr(flag-22) temp CATSTR @SubStr(<%temp>,var) flag CATSTR <23> var CATSTR <0> ELSE var CATSTR %@CatStr(23-flag) ENDIF ;---------------------------- mant CATSTR <> REPT flag mant CATSTR mant,@SubStr(<%temp>,flag,1) flag CATSTR %@CatStr(flag-1) ENDM ;---------------------------- :nxt1 ;--------------------------------- temp CATSTR %@SizeStr(<%buf>) ;--------------------------------- IF temp EQ 1 goto nxt4 ENDIF ;--------------------------------- :nxt5 IFIDNI @SubStr(<%buf>,temp,1),<0> temp CATSTR %@CatStr(temp-1) IF temp EQ 1 goto nxt4 ENDIF goto nxt5 ENDIF ;--------------------------------- :nxt4 ;--------------------------------- buf CATSTR @SubStr(<%buf>,1,temp) ;--------------------------------- flag CATSTR <1> REPT temp flag CATSTR flag,@CatStr(<0>) ENDM ;--------------------------------- temp CATSTR <0> :nxt6 IF var EQ 24 temp CATSTR %@CatStr(temp+1) buf CATSTR %@CatStr(buf shl 1) IF @CatStr(buf/flag) EQ 1 exp CATSTR %@CatStr(127-temp) var CATSTR <23> ENDIF buf CATSTR %@CatStr(buf MOD flag) goto nxt6 ENDIF ;--------------------------------- temp CATSTR <> :nxt7 IF var NE 0 buf CATSTR %@CatStr(buf shl 1) temp CATSTR temp,%@CatStr(buf/flag) buf CATSTR %@CatStr(buf MOD flag) var CATSTR %@CatStr(var-1) goto nxt7 ENDIF ;--------------------------------- buf CATSTR %@CatStr(buf shl 1) dop CATSTR %@CatStr(buf/flag) ;--------------------------------- flag CATSTR <> REPT 8 flag CATSTR flag,%@CatStr(@CatStr(exp MOD 2)) exp CATSTR %@CatStr(exp/2) ENDM ;--------------------------------- buf CATSTR <znak> ;--------------------------------- var CATSTR <8> REPT 8 buf CATSTR buf,@SubStr(<%flag>,var,1) var CATSTR %@CatStr(var-1) ENDM ;--------------------------------- buf CATSTR buf,mant,temp,<b> ;--------------------------------- var CATSTR %@CatStr(buf+dop) ;--------------------------------- EXITM <var> ;--------------------------------- ENDM
Если кому интересен алгоритм Тажа макрофункция но только с моими коментариями Код (ASM): @NumberReal4 MACRO p1:REQ local znak,buf,var,temp,mant,flag,exp,dop ;--------------------------------- ; если первый символ параметра минус (-) ; значит число отрицательное ; результат запишем в макропеременную - znak ; если отрицательное запишем (1) ; если положительное запишем (0) ;--------------------------------- IF @InStr(1,<p1>,<->) EQ 0 znak CATSTR <0> ELSE znak CATSTR <1> ENDIF ;--------------------------------- ; перепишем параметр отбросив символы пробела < > ; символ минуса <-> или символ плюса <+> ; результат запишем в макропеременную - buf ;--------------------------------- buf CATSTR <> FORC var,<p1> IF @InStr(1,< -+>,<var>) EQ 0 buf CATSTR buf,<var> ENDIF ENDM ;--------------------------------- ; узнаем по какому смещению находится точка ; результат запишем в макропеременную - temp ;--------------------------------- temp CATSTR %@InStr(1,<%buf>,<.>) ;--------------------------------- ; число до точки это целое число ; результат запишем в макропеременную - mant ;--------------------------------- mant CATSTR %@SubStr(<%buf>,1,temp-1) ;--------------------------------- ; если число символов целого числа больше (9) ; макрос на этапе компиляции выдаст ошибку ; <Real4 - много аргументов в целом числе> ;--------------------------------- IF @SizeStr(<%mant>) GT 9 .ERR <Real4 - many symbol in integer> ENDIF ;--------------------------------- ; число после точки это дробное число ; результат запишем в макропеременной - buf ;--------------------------------- buf CATSTR @SubStr(<%buf>,temp+1) ;--------------------------------- ; если число символов дробной части числа больше (9) ; макрос на этапе компиляции выдаст ошибку ; <Real4 - много аргументов в дробной части> ;--------------------------------- IF @SizeStr(<%buf>) GT 9 .ERR <Real4 - many symbol in fractional part> ENDIF ;--------------------------------- ; анализ и обработка целого числа ; из макропеременной - mant ; если целое число ноль (0) ; то макропеременную - mant ; мы сделаем пустышкой ; а в макропеременную - var ; пропишем число (24) ; и сделаем переход на метку - nxt1 ;--------------------------------- IF mant EQ 0 mant CATSTR <> var CATSTR <24> goto nxt1 ENDIF ;---------------------------- ; если целое число не ноль ; двоичное представление целого числа ; в обратном порядке ; запишем в макропеременную - temp ;---------------------------- flag CATSTR <0> temp CATSTR <> :nxt2 temp CATSTR temp,%@CatStr(@CatStr(mant MOD 2)) mant CATSTR %@CatStr(mant/2) IF mant EQ 0 goto nxt3 ENDIF flag CATSTR %@CatStr(flag+1) goto nxt2 :nxt3 ;---------------------------- ; после обработки в макропеременной - flag ; будет число символов двоичного целого числа ; минус один символ последнего бита ; это число также можно считать смещением экспоненты ; базовая экспонента (Real4) это число (127) ; прибавим к базовой экспоненте смещение ; и сохраним результат в макропеременной - exp ;---------------------------- exp CATSTR %@CatStr(127+flag) ;---------------------------- ; под мантису одинарной точности выделяется (23) бита ; если число смещения больше (23) ; тогда перепишем макропеременную - temp ; насколько число смещения больше числа (23) ; настолько мы и обрежем первые биты ; обратного порядка числа ; а так как число бит в мантисе ; не должно быть больше (23) ; то соответственно в макропеременную - flag ; мы запишем (23) ; также в процессе обработки мы должны выяснить ; какое число бит в мантисе нам останется под ; двоичное представление дробной части числа ; и это число мы запишем в макропеременную - var ; по этому если число смещения больше числа (23) ; мы запишем туда ноль (0) ; а если число смещения не больше ; тогда просто посчитаем сколько бит нам осталось ; и соответственно запишем это значение ; в макропеременную - var ;---------------------------- IF flag GT 23 var CATSTR %@CatStr(flag-22) temp CATSTR @SubStr(<%temp>,var) flag CATSTR <23> var CATSTR <0> ELSE var CATSTR %@CatStr(23-flag) ENDIF ;---------------------------- ; в макропеременную - mant ; перепишем двоичное представление целого числа ; уже в правильном порядке ; кроме числа первого бита ; которое если число не ноль всегда равен (1) ; и в мантисе эта единица ; по умолчанию просто представляется ; число бит находится в макропеременной - flag ;---------------------------- mant CATSTR <> REPT flag mant CATSTR mant,@SubStr(<%temp>,flag,1) flag CATSTR %@CatStr(flag-1) ENDM ;---------------------------- :nxt1 ;--------------------------------- ; будем работать с дробной частью числа ; в макропеременную - temp ; запишем сколько символов в макропеременной - buf ; это нужно только для того если в дробной чати числа ; указаны лишнии конечные нули ;--------------------------------- temp CATSTR %@SizeStr(<%buf>) ;--------------------------------- ; если символ всего один (1) ; то переходим на метку - nxt4 ;--------------------------------- IF temp EQ 1 goto nxt4 ENDIF ;--------------------------------- ; если символов больше чем один то начиная с конца ; будем искать конечные лишнии нули ; если нулей нет то символы переменной не изменятся ; если есть то символы уменьшатся на количество нулей ; но в любом случае должно остатся ; не меньше одного символа ;--------------------------------- :nxt5 IFIDNI @SubStr(<%buf>,temp,1),<0> temp CATSTR %@CatStr(temp-1) IF temp EQ 1 goto nxt4 ENDIF goto nxt5 ENDIF ;--------------------------------- :nxt4 ;--------------------------------- ; на основе значения макропеременной - temp ; перепишем данные в макропеременной - buf ;--------------------------------- buf CATSTR @SubStr(<%buf>,1,temp) ;--------------------------------- ; зная значение числа макропеременной - temp ; мы каждый раз к текстовой единице ; будем в конце приписывать ноль (0) ; тем самым сформируем число деления дробной части ; и запишем это число в макропеременную - flag ;--------------------------------- flag CATSTR <1> REPT temp flag CATSTR flag,@CatStr(<0>) ENDM ;--------------------------------- ; если макропеременная - var ; равна (24) ; значит целая часть числа равна нулю (0) ; в этом случае нам нужно будет искать число ; смещения экспоненты в отрицательную сторону ; для этого нам нужно будет начать ; раскладывать дробное число на двоичные разряды ; до тех пор пока не встретится первая единица (1) ; каким символом по счёту будет первая единица (1) ; такое и будет число смещения экспоненты ; это число отнимем от базовой экспоненты (127) ; и у нас получится отрицательная экспонента ; результат мы запишем в макропеременную - exp ; после отработки этого условия ; разложение дробной части числа на двоичные разряды ; и запись этих разрядов в мантису ; продолжится сразу же после этой первой единицы (1) ; мантису мы должны заполнить по полной ; то есть все её (23) бита ; по этому в этом условии при нахождении единицы (1) ; в макропеременную - var ; мы запишем число (23) ;--------------------------------- temp CATSTR <0> :nxt6 IF var EQ 24 temp CATSTR %@CatStr(temp+1) buf CATSTR %@CatStr(buf shl 1) IF @CatStr(buf/flag) EQ 1 exp CATSTR %@CatStr(127-temp) var CATSTR <23> ENDIF buf CATSTR %@CatStr(buf MOD flag) goto nxt6 ENDIF ;--------------------------------- ; в макропеременную - temp ; запишем дробную часть числа в двоичном формате ; но запишем ровно столько бит ; сколько указано в значении макропеременной - var ;--------------------------------- temp CATSTR <> :nxt7 IF var NE 0 buf CATSTR %@CatStr(buf shl 1) temp CATSTR temp,%@CatStr(buf/flag) buf CATSTR %@CatStr(buf MOD flag) var CATSTR %@CatStr(var-1) goto nxt7 ENDIF ;--------------------------------- ; у дробной части числа ; сверх отведённого лимита проверим следующий бит ; двоичное значение этого бита (0) или (1) ; запишем в макропеременную - dop ; в конце мы к десятичному результату ; прибавим это значение к конечному результату ; то есть как бы округлим если бит (1) ; или нет если бит (0) ;--------------------------------- buf CATSTR %@CatStr(buf shl 1) dop CATSTR %@CatStr(buf/flag) ;--------------------------------- ; в двоичном формате в обратном порядке ; запишем экспоненту в макропеременную - flag ; для экспоненты выделяется восемь символов (8 бит) ;--------------------------------- flag CATSTR <> REPT 8 flag CATSTR flag,%@CatStr(@CatStr(exp MOD 2)) exp CATSTR %@CatStr(exp/2) ENDM ;--------------------------------- ; здесь будем собирать результат (32 бита) ; в макропеременную - buf ; сначала запишем первый бит знака ; из макропеременной - znak ;--------------------------------- buf CATSTR <znak> ;--------------------------------- ; потом добавим восемь бит ; экспоненты в правильном порядке ;--------------------------------- var CATSTR <8> REPT 8 buf CATSTR buf,@SubStr(<%flag>,var,1) var CATSTR %@CatStr(var-1) ENDM ;--------------------------------- ; после припишем мантису (23 бита) ; она будет состоять из двоичных данных ; целого числа из макропеременной - mant ; и двоичных данных дробной части ; которые были записаны на оставшихся битах ; из макропеременной - temp ; и в конце по правилам синтаксиса ; для двоичного числа припишем постфикс <b> ;--------------------------------- buf CATSTR buf,mant,temp,<b> ;--------------------------------- ; полученное 32 битное двоичное значение числа ; по умолчанию переведём в десятичный формат ; и прибавим к результату дополнительное число ; если дополнительное число (1) ; то результат прибавится на единицу ; а если дополнительное число (0) ; то мы к результату прибавим просто ноль ; результат пропишем в макропеременную - var ;--------------------------------- var CATSTR %@CatStr(buf+dop) ;--------------------------------- ; на выходе макрофункция вернёт десятичное число ; указанного в параметре числа с плавающей точкой ;--------------------------------- EXITM <var> ;--------------------------------- ENDM
В макросе - @NumberReal4 нашёл небольшие ошибки из за которых в некоторых случаях не коректно отрабатывается алгоритм сам я изменить пост № 10 и № 11 не могу по этому если кому надо выставляю ссылку https://yadi.sk/d/dXBlunel3CyfFG там файл в котором исправленный алгоритм макроса плюс тот же макрос с коментариями