Деление и умножение чисел с дробной частью, не равной степени двойки?

Всем привет!
Мне в универе задали бахнуть программу (NASM, x86, Intel 80386), которая берет из стака два 64 битных значения, в каждом из которых 18 нижних битов отведены под дробную часть, а остальные — целую, и перемножает \ делит их.

Как лучше всего прописать умножение и деление?
Как это сделать с числами с фикс. запятой (8.8, 16.16, 32.32) я понимаю, но с .18 — нет.
Спасибо!

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Как это сделать с числами с фикс. запятой (8.8, 16.16, 32.32) я понимаю, но с .18 — нет.

Нет, не понимаешь. Разницы нет.

Умножение:
1) Умножаешь два 64 битный числа, получаешь 128 битный результат.
2) Сдвигаешь 128 битный результат вправо на 18 бит.
3) Следи за тем знаковые числа или нет.

Деление:
1) Сдвигаешь влево на 18 бит делимое (64 битное значение), все выпавшие биты засовываешь в новое 64 битное значение и получаешь 128 битное значение.
2) Делишь 128 бит на 64
3) Следи за тем знаковые числа или нет.

Теперь самое сложное 64 битовая арифметика с 32 битовыми значениями.
1) Сдвиги — чисто алгоритмическая операция, берешь старшие разряды 32 битового значения и копируешь в младшие разряды следующего 32 битового значения при сдвиге влево и наоборот при сдвиге вправо. Препод на 5 хочет видеть SHLD/SHRD операции.
2) Сложение и вычинание, умножение и деление — делай в столбик, как в школе, только вместо разрядов со значениями 0-9 используй все 32 битовое число.

Если не осилишь деление в столбик смотри алгоритм: binary division by shift and subtract.

Ничего сложного в этом нет. Это уровень 8 класса школы. Но работа по сути обезьянья, сводится к отладке. Вся её цель — тупо потратить время и сгенерить ошибки, чтобы доказать студенту что он должен заплатить. Потому проще заплатить сразу, время дороже. Ладно бы что-то нужное давали.

Но разница в том, что это не институт, а универ. Совершенно другого класса образование, включающее И гуманитарный цикл. Потому на 5+ нужно не сделать эту работу, а оптимизировать. Например, купить готовую у предыдущих курсов. Или же вообще добиться исключения курса тупорылого ассемблера х86 и его препода с факультета, ежели эта обезьянка не способна преподавать тот же ассемблер, но уже под embedded устройства, где он вполне даже может пригодиться, особенно если есть желание выпустить что-то реально рабочее и супер-дёшево.

То есть задачу можно решить технически, можно гуманитарным. Лично я бы выбирал гуманитарный путь, потому что в универ люди приходят ещё и за образованием, а не только за корочкой. И пока учишься, есть большой грех упустить возможность потестить свои навыки, начиная от логики и кончая юриспруденцией. Хотя на этом пути и можно натворить ошибок, ни одна из них не будет стоить столько, сколько лишение себя гуманитарной части образования, учась в универе.

В наше время как раз технические знания являются софт-скиллом, который надо постоянно менять и обновлять, притом под совершенно разные запросы и нет никакого способа предсказать что именно понадобится дальше, тем более выучить «на будущее». А вот гуманитарка — реальная база, без которой невозможно даже выживать в среде тотального идиотизма, не говоря уж об умении строить «зону комфорта» в самых любых рабочих условиях, и понимать когда имеет смысл менять ситуацию под себя, а когда надо драть когти аки крыса с тонущего корыта.

PS. О снижении точности никто не говорил, почему результат не может оказаться с точностью 36 знаков после запятой, а не 18? Не нужно придумывать себе лишнего. Всё равно ж куда-то придётся девать и старшие биты, теоретически не попадающие в размерность. А это лишний геморой с выяснением условия.

Давай, расскажи, сколько ты заработал ассемблером 80386? Я не говорю «на пиво», хотя бы на стеклотару от пива хватит?

Коментар порушує правила спільноти і видалений модераторами.

есть различие : в 80386 нет 64-битных регистров, и поэтому напрямую перемножить 64-битные числа не получится.
Я как раз на этом и застрял :(

есть различие : в 80386 нет 64-битных регистров, и поэтому напрямую перемножить 64-битные числа не получится.

Я ж тебе написал — в столбик делай, ну или напиши на С и дизассемблируй или пользуйся gcc -S он тебе сгенерит ассемблер в исходнике.

Но в столбик умножать тоже можно, только мне не совсем ясно условие насчет дробной части... но если дробная часть простая, как здесь пишут, то я бы попробовал так:
Если X * Y = Z , то X и Y сохраняем в ячейки памяти (для X нужно 128 бит = 0, для Y достаточно 64 бит) а 128 бит Z будем аккумулировать, например, в edx:ecx:ebx:eax или в памяти (в регистрах, по-идее, будет и быстрее и удобнее).
Потом делаем 64 сдвига Y вправо (и, соотв., 63 сдвига влево X) и на каждой итерации суммируем Z с X, если конечно флаг после сдвига Y = 1.
При сложении не теряйте carry flag (почитайте CF, ADC), кроме первого слова (ADD).
И, как уже писали, у результата отбрасываем лишние 18 битов дробной части (сдвигаем вправо).
В каких-то деталях я могу ошибаться, давно уже использовал ASM, и тогда я не использовал dword регистры и 80386, так что будьте внимательны.

Мой совет, купи оценку по этому предмету и не занимайся шизой. Тебе НИКОГДА не придётся писать на х86 ассемблере. Достаточно того, что ты представляешь в принципе, как что работает. Тем более тебе никогда не придётся писать под проц, не поддерживающий работу с числами с плавающей точкой.

Подсказка: числа с фиксированной точкой попросту НЕ ЗНАЮТ, что у них есть точка. Грубо говоря, в вычислении площади 1.020м*0.855м и вычислении 1020мм*855мм нет разницы в результате. То есть о наличии запятой знаешь только ты. И все вычисления с фиксированной точкой являются целочисленными по сути.

Как ты догадываешься, 64*64 бита — это 128 бит. Да, ты можешь по итогу отсечь младшие разряды. Но ЧТО ДЕЛАТЬ со старшими — тебе не сказали. А зря. Должны были. Конечно, ты можешь вызвать исключение, но ты уверен, что это то что тебе надо? В обычных языках программирования соглашение такое: все промежуточные вычисления выполняются с двойной точностью. То есть ассемблерная команда умножения даст тебе 128 бит, а уже далее ты должен что-то проверить и что-то сделать зависимо от результата проверки.

386, если не изменяет память, 32-битный, это немного сокращает код. То есть грубо говоря, тебе как в школе в столбик нужно перемножить числа по 32 бита в разряде. Да, да, с теми самыми «два пишем, три в уме». Но здесь нет «в уме», здесь есть двойная точность. При сомножении 32*32 младших DWORD бита ты получаешь 64-битное целое. Заведомо усечь дробную часть на 18 бит тебе не поможет НИЧЕМ, потому что ты всё равно можешь получить переполнение. И вот я не помню, что возвращает 80386 в этом случае — честный результат В ДВУХ регистрах, или же исключительную ситуацию. Если исключительную — тебе придётся считать разрядами по 16 бит, а не по 32. Ну а дальше по классике: складываешь и сдвигаешь.

Если тебе дополнительные условия НЕ заданы, ты вполне можешь выдать результат в текстовом формате, то есть в 8-битной кодировке, выполняя последовательно деление с остатком целой и дробной части на 10, вывести их, вставив между ними точку и добавив код символа ’0′ к каждому разряду. Текстовый формат избавит тебя от проверки ограничений (и выяснения, что с ними сделать).
_______________________
ЕСЛИ НЕ можешь купить оценку — купи выполнение задачи у того, кто будет это делать. Поверь, сделать кучу однотипных задач одному человеку гораздо проще, чем каждому этим бредом прошлого века заниматься и учиться тому, что понадобится реже чем умение играть членом на рояле (ну есть же шанс что захочешь стать президентом).

Мой совет, купи оценку по этому предмету и не занимайся шизой

Как тут дизлайк поставить?

Тебе НИКОГДА не придётся писать на х86 ассемблере. Достаточно того, что ты представляешь в принципе, как что работает.

Вопрос же состоит в том, чтобы показать что ТС понимает как работает, а x86 — камень который уже есть у студентов (в отличии от какой-нибудь ардуины)

Тем более тебе никогда не придётся писать под проц, не поддерживающий работу с числами с плавающей точкой.

Инфа сотка?

(в отличии от какой-нибудь ардуины)

32-хбитная Ардуина стоит порядка 500 гривен. 8-битная — гривен 100-200.
На самом деле (ИМХО, конечно же), написание на ассемблере под ардуину имело бы больше смысла. Ближе к железу, понятнее зачем нужно выжимать каждую кроху производительности. Сложнее списать xD

Инфа сотка?

Если готовят очередную партию «установщиков npm-пакетов» — то да, инфа сотка.

32-хбитная Ардуина стоит порядка 500 гривен. 8-битная — гривен 100-200.

У студента нет таких денег, у вуза — тем более

написание на ассемблере под ардуину имело бы больше смысла

В сферическом вакууме — да. На практике — принципиальной разницы нет

Если готовят очередную партию «установщиков npm-пакетов»

Фу

у меня еще практика по ассемблеру + С будет, эта часть твоего коммента иррелевантна.

С это вполне даже понятный язык. А вот задачки уровня 80х годов прошлого века — пора бы оставить в пыли времён. Если уж ставить задачи на ассемблер, то и условия должны соответствовать ассемблерным задачам. А именно: достигнуть СКОРОСТИ выполнения, то есть задачи должны быть АЛГОРИТМИЧЕСКИМИ, а не обезьяньей работой как в твоём случае.

И я повторюсь, львиная доля твоей задачи заключается в некорректном условии, то есть тебе специально поставили задачу таким образом, чтобы решить ты её не мог без «индивидуального подхода к каждому клиенту», чтобы к её решению всегда можно было прикопаться.

Тем более тебе никогда не придётся писать под проц, не поддерживающий работу с числами с плавающей точкой.

На самом деле нет. Финансовые операции через floating point в программах делаю только особо одарённые люди. Плавающая запятая на то она и плавающая, что точность в диапазоне 0.0..1.0 гораздо выше чем точность в миллиардах. Плюс двоичное, а не десятичное основание плавающей запятой делают записи типа 10 центов как 0.1f убийством при котором ты начнёшь терять бабки.

Fixed point — это двоичный вариант, в десятичном просто каждое число умножают на 1000000, а не на 2^18, например, и ведут те же самые операции с интежерами.

Увы, по сей день нет вменяемого ОБЩЕПРИНЯТОГО стандарта чисел с фиксированной точкой в языках программирования. Вот чтоб пользоваться ими как обычными, а железяка уже под ковром делала чёрную работу. Почему-то это даже в калькуляторе есть, а в том что сложнее — нет.

Хотя казалось бы, что стоит состряпать класс под такие числа. А вот состряпать стандарт...

Коментар порушує правила спільноти і видалений модераторами.

Мой совет, купи оценку по этому предмету и не занимайся шизой. Тебе НИКОГДА не придётся писать на х86 ассемблере.

🤦
Ваш ответ, это такое дно..

Сначала выучи ассемблер 80386 процессора, потрать на это туеву хучу времени, потом расскажешь за дно.

В чем проблема? Я знаю ассемблер x86 и базовый 386 (без деталей real/protected/virtual mode)

потрать на это туеву хучу времени

во-первых ассемблер — это элементарно, там нечего учить особо
во-вторых — это просто интересно

Моя претензия к вашему совету «купить оценку», человеку, который пытается разобраться.

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

Ну так ты ж не стал вместо API учить ассемблер?

Я дизассемблировал системы либы/сервисы, чтобы понять чего они там в доках недописали

Назови того, кто заплатил тебе в итоге за эти знания? И сколько?

??

Вы хотите сказать, что за «знание чего-то» вам должны заплатить?
Или что время потраченное на «изучение чего-то» должно себя окупить?
Или указать, как пример, что это «бесполезное знание»?

Или указать, как пример, что это «бесполезное знание»?

да, он это и имеет в виду. Нет, я с ним не согласен, так что со мной спорить будет бесполезно.

Ну я считаю, что постоянно на этом зарабатываю — но не напрямую написанием на нём, а тем, что знаю, как на ЯВУ написать так, чтобы было быстро, и могу это проверять. И это нормально для... ну да, меньше половину (современному фронтэнду — пофиг), но таки для достаточного числа людей.

(без деталей real/protected/virtual mode)

Ассемблер там одинаковый кроме магии нужный битик в нужном регистре выставить

Адресация разная.
Помню, что так и не разобрался, на какие таблицы какие сегментные регистры должны указывать.
Когда-то был целый класс програм dos-extenders, и они были весьма сложнее, чем

нужный битик в нужном регистре выставить

Это то, что я назвал магией)

Это не магия. Просто очень специфическое знание.

В ассемблере разное очень много, если ты его для дела учишь, а не просто УБИТЬ ВРЕМЯ ради показухе в ВУЗе, который какого-то хера этим занимается.

Грубо говоря, на ассемблере ты разговариваешь с самим железом, с его особенностями, и ИСКЛЮЧИТЕЛЬНО ради этих особенностей вообще берёшь в руки ассемблер. Для всего остального есть С.

Вы путаете «программирование на ассемблере» и «знание ассемблера».
Например, как без знания ассемблера написать на С кодогенерацию?

Какую ещё кодогенерацию? Ассемблер это всегда конкретика. И я не против изучения ассемблера, но ИМЕННО ТОГО ассемблера, который нужен. И тогда, когда нужен. Иными словами, либо изучать с практическим применением, или нуегонафих.

Особое внимание: чаще всего ассемблер применяется для устройств с весьма ограниченным функционалом, и как следствие, ценой. Соответственно, и набор команд там сильно другой, чем в полноценном 80386. Либо наоборот, для устройств с расширенным функционалом, под эффективную работу с которым тупо нет библиотек, или ты сам пишешь/правишь эти самые библиотеки.

Какую ещё кодогенерацию?

Которая AST в машинный код транслирует.

Но, кажется, я понял, о чем вы пишете — «если под какую-то архитектуру процессора, есть (вменяемый) C компилятор, то „ассемблер“ не нужен».
Если так, то это весьма субёктивное мнение, которым не стоит сильно размахивать.

В большинстве случаев С достаточно, а кодогенерацией занимается меньше чем 1 из миллиона. Конкретно ты — не занимаешься. Ассемблер нужен чтобы использовать архитектурные особенности железа, ЛИБО чтобы дизассемблировать код (для взлома или исследования). И здесь нельзя запрягать лошадь вперёд локомотива, потому что так вместо знаний будет получена вакцина от знаний.

Мой совет, купи оценку по этому предмету и не занимайся шизой. Тебе НИКОГДА не придётся писать на х86 ассемблере. Достаточно того, что ты представляешь в принципе, как что работает. Тем более тебе никогда не придётся писать под проц, не поддерживающий работу с числами с плавающей точкой.

Вебмакака. Начало.
Экземпляр, не освоивший хотя бы один ассемблер (одного достаточно, хотя я за время обучения в вузе освоил целых 3) это просто туповатый свитчер, а не айтишник.

хотя я за время обучения в вузе освоил целых 3

И теперь макака с иллюзией знания трёх ассемблеров

Тебе НИКОГДА не придётся писать на х86 ассемблере. Достаточно того, что ты представляешь в принципе, как что работает.

не согласен. И мой поинт не в «ты должен понимать, как работает в машинных кодах»
— само по себе это херовый аргумент. Но! Я часто(реально чаще, чем хотелось б) встречаю людей в IT которые к разработке относятся как к магическому черному ящику. Крайний вариант — это когда гуглят готовые решения и сразу вставляют в код. Ну, и не такие драматические варианты тоже.

При чем тут ассемблер? Это один из путей, как по мне — один из самых простых, осознать, что внутри это просто огромный калькулятор с ограниченным набором базовых операций, простых как двери. Из тех вещей, что словами говорить бесполезно, если такого ощущения еще нет.

Обязательно ли каждому проходить через практику, бесполезную в работе? Не обязательно — некоторые и так уже в курсе, что комп — большой калькулятор. Поможет ли всем «шаманам от IT»? Нет. Но точно кому-то поставит мозги.

Для этого не нужно целый курс отдавать да ещё с практическими задачами. Достаточно одной ознакомительной лекции. В школе.

Это я могу знать, что железяка из арифметики умеет только складывать и сдвигать. Потому что у меня университетское образование, оно не совсем ITшное. Но те кто учится чисто под рынок, кто никогда не будет писать близкий к железу код, кто верит что Абстрактный класс и Интерфейс — это две диаметрально разные сущности, или что ООП защищает код он несанкционированного исполнения — зачем им всё это?

Они ведь религии учатся по сути. Как правильно заметили, веб-макаки. Им нужно верить что всё работает ровно вот так, как написано. А через год — по-другому. Ещё через год — «забудьте чему вас учили».

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

Достаточно одной ознакомительной лекции.

Не согласен. Это концептуальный момент, как, например, рекурсия, монады или ООП. Просто заучить определения недостаточно. Врачи вон после 6 лет обучения и кучи лет практики вполне могут _искренне_ пропихивать гомеопатию какую-то. Хотя им и физиологию и прочие основы давали.

Причина в аккурат в этом. То что выучили нормально — забывается за 2 года до невозможности применимости, за 3 года — до уверенности в незнании. А то что выучили КАК ПОПАЛО, по большому счёту тупо надиктовали конспект и задали выполнить херню — формирует ИММУНИТЕТ к знаниям и шаблон запрета в памяти закладывать в память что-то связанное с этой хренью.

Выученная беспомощность — вот что такое эта методика образования. А почему до сих пор применяется? Да как раз поэтому, что никто не возражает, считая себя виновных в непонимании предмета. О том что его не надо было понимать они догадаются много позже.

Это всё равно что во 2м классе заставлять школьников писать сочинения про осень. Они не знают, что такое осень, потому что для них время ещё идёт слишком медленно. Они никогда не готовились ни к осени, ни к зиме. Так же и учить ассемблер бесполезно тем, кто не столкнулся с задачами низкоуровневых ограничений. А учитывая что львиная доля веб-макак никогда с этим и не столкнётся — давать нужно ассемблер в рамках университетского курса, не институтского. И разумеется тот ассемблер, который будет нужен.

А если же препод не может/не хочет переучиться под новый ассемблер — гнать такого ссаными тряпками, не умеющий учиться не имеет права учить, ибо не понимает природы обучения. Сегодня если ассемблер и учить, то ARM, ибо рынок никогда не ошибается (он сам и есть критерий ошибки).

вообще не понял, при чем тут дихотомия новый-старый ассемблер. Я говорил исключительно о пользе от изучения низкоуровневого программирования. ARM или х86 — не принципиально вообще. arduino правда, нагляднее, чем древние эмуляторы 8086, плюс можно зафигачить полноценную систему заодно.

Именно это и принципиально. Разница в том, получишь ты образование или иммунитет от образования.

оке-оке, сходимся на том, что ассемблер под ARM таки нужен, и закрываем тред по согласованию сторон?

я просто не заметил акцента на «х86» в исходном сообщении, а увидел только акцент на ассемблере, вот и вклинился.

ассемблер под ARM таки нужен, и закрываем тред по согласованию сторон?

Не нужен. Код пишется на C — этого достаточно (в т.ч. для написания эмбеда).

Да, ассемблер полезно уметь читать (скажем, для оптимизации сишного кода) — но за любые ассемблерные вставки в продакт коде, будут больно бить по рукам.

А уж написание программ на ассемблере — это вообще давно забытый и никому не нужный (за исключением одного кодера из сотни тысяч) скилл.

Понятное дело, что при помощи масок или сдвигов можно получить нужные 32/18/14 битов, а как потом результаты в одну кучу собрать?
---
И нет, перемножить попарно 32 бита и сложить результат не пойдет : может быть такое, что у одного числа дробная часть есть, а у второго — нет, и такое перемножение приведёт не к тому результату.

Именно так и нужно сделать. Вспомни, как множат в столбик: НЕ ОБРАЩАЯ ВНИМАНИЯ на запятую. Её ставят в конце. В твоём случае — 36 разрядов с конца. Если надо меньше — зря ты не спросил, как надо округлить, потому что тебе придётся это делать.

Только я не вижу в твоём условии вообще указания, что точка фиксированная. Но если бы была плавающая, подразумевалось бы несколько бит под указание положения точки.

Підписатись на коментарі