Разделение и округление в сборке

У меня есть два номера (DWORD number_A и DWORD number_B). Я не уверен, как разделить два, чтобы получить десятичное число, округленное до ближайшей тысячной.

(ie)

DWORD number_A 20
DWORD number_B 10

A/B = 2.00 - это формат ответа, который я пытаюсь получить.

Как мне разделить, а затем отобразить ответ, как указано выше, на языке ассемблера? Мы также используем библиотеку irvine, если это поможет.


person Community    schedule 10.04.2020    source источник
comment
stackoverflow.com/questions/3027424/, возможно, это поможет   -  person KagurazakaKotori    schedule 10.04.2020
comment
Требует ли ваш курс использования устаревшей архитектуры x87 или вы можете использовать SSE2 cvtsi2sd и divsd для преобразования в double в регистрах XMM? felixcloutier.com/x86/cvtsi2sd   -  person Peter Cordes    schedule 10.04.2020
comment
2.00 будет округлено до сотых? Вы можете использовать арифметику с фиксированной точкой, вычислять деление целыми числами (например, использовать центы вместо долларов), но выводить с расширением . между. Перед делением вы должны умножить на 100/1000 (см. строку ответа @Chris Halls 3). Для вывода вы можете разделить на 100/1000 с остатком и поставить десятичную точку между ними.   -  person Sebastian    schedule 10.04.2020
comment
@Sebastian: FWIW, если вы умножаете на 100/1000 перед делением на B, деление может завершиться ошибкой, если B ‹ 100/1000, а A достаточно велико. Я расширил свой ответ, чтобы обсудить это.   -  person Chris Hall    schedule 11.04.2020


Ответы (1)


Если вы хотите сделать это с помощью целочисленной арифметики, то (метод 1):

  q = A / B      -- integer division  ) assuming unsigned numbers, that's
  r = A % B      -- integer remainder ) q = eax and r = edx after a DIV

  r = r * 1000
  f = r / B      -- also integer division/remainder, as above
  r = r % B

  f += ((r * 2) >= B)  -- where >= returns 0 or 1

  if (f > 999) { q += 1 ; f = 0 ; }

затем выведите q, за которым следует '.', а затем 3 цифры для f с начальными нулями, как требуется.


Вы также можете выполнить округление и дробную часть следующим образом (метод 2):

  q = A / B          -- as above
  r = A % B

  r = r * 2000
  f = r / B          -- result f is in half-thousandths
  f = (f + 1) >> 1   -- round to nearest thousandth

  if (f > 999) { q += 1 ; f = 0 ; } 

В этой и предыдущей формах, если B (очень) велико, r * 2000 (и действительно r * 1000) может быть больше 32 бит, но это нормально, потому что DIV справится с 64-битным делимым, при условии, что частное меньше 2^32 -- и мы знаем, что частное в этом случае меньше 2000 (или 1000).


Как отмечалось в другом месте, вы также можете сделать это (метод 3):

  A = A * 1000
  q = A / B
  r = A % B

  q += ((r * 2) >= B)  -- where >= returns 0 or 1

  f = q % 1000         -- alternatively, when outputting, convert f to  
  q = q / 1000         -- decimal and insert '.' before last 3 digits

И, как вариант (метод 4):

  q = (A * 2000) / B   -- again half-thousandths
  q = (q + 1) >> 1     -- round to nearest thousandth

НО: деление завершится ошибкой, если A * 1000 (или A * 2000) больше или равно B * 2^32, потому что q больше или равно 2^32.

Преимущество методов 1 и 2 в том, что они не сбиваются с толку таким образом.

person Chris Hall    schedule 10.04.2020
comment
Стоит упомянуть, что f = (f + 1) >> 1 и последующее исправление всей части выполняют округление до ближайшего четного вместо усечения. - person Peter Cordes; 11.04.2020
comment
@PeterCordes: f = (f + 1) >> 1 (метод 2) имеет f в полтысячных, поэтому это добавляет полтысячные (` + 1) and truncates to thousandths ( ›› 1`), чтобы выполнить обычное округление до ближайшего (т.е. не округление до ближайшего-четного). (Аналогично способ 4.) - person Chris Hall; 11.04.2020
comment
О верно. Стоит объяснить это в вашем ответе, ИМО, и, возможно, даже показать простую версию, которая позволяет выполнять усечение. - person Peter Cordes; 11.04.2020
comment
@PeterCordes: ОК, добавил несколько комментариев о полутысячных. ОП попросил округлить до тысячных ... так что не убежден, что показ того, как усекать до тысячных, приносит много пользы вечеринке. - person Chris Hall; 11.04.2020
comment
Я пропустил эту фразу. Вероятно, ОП - новичок, выполняющий домашнее задание, который не знает разницы между округлением и усечением и просто думал о том, чтобы каким-то образом получить результат с 3 знаками после запятой. Вот почему я подумал, что было бы полезно показать простую версию, которая не включает округление до ближайшего. Но, конечно, это более чем хорошо, как рецепт. Я мог бы включить некоторый текст, чтобы хотя бы указать, что округление до ближайшего требует больше работы, чем усечение, и как это достигается. Но тогда потребовалось бы слишком много усилий, чтобы ответить на этот вопрос. :/ - person Peter Cordes; 11.04.2020