128-битное деление, присущее Visual C ++ - PullRequest
10 голосов
/ 10 декабря 2011

Мне интересно, нет ли в Visual C ++ встроенной функции 128-битного деления?

Существует встроенная функция умножения 64x64 = 128 битов, называемая _umul128(), которая хорошо соответствует инструкции ассемблера MUL x64.

Естественно, я предполагал, что будет 128/64 =Также есть встроенное 64-битное деление (моделирование инструкции DIV), но, к моему изумлению, ни Visual C ++, ни Intel C ++, похоже, не имеют его, по крайней мере, его нет в intrin.h.?Я попробовал grep'ing для имен функций в исполняемых файлах компилятора, но не смог найти _umul128, поэтому, я думаю, я посмотрел не туда.

Обновление: по крайней мере, у меня естьтеперь нашел шаблон umul128 (без начального подчеркивания) в c1.dll Visual C ++ 2010. Все остальные встроенные функции перечислены вокруг него, но, к сожалению, нет «udiv128» или чего-то подобного :( Так что, похоже, они действительно забыли »"чтобы реализовать его.

Чтобы уточнить: я не только ищу 128-битный тип данных, но и способ делить 128-битное скалярное int на 64-битное int в C ++. встроенная функция или собственная 128-разрядная целочисленная поддержка решит мою проблему.

Редактировать: Ответ - нет, нет _udiv128 встроен в Visual Studio 2010 до 2017 года, но доступен в Visual Studio 2019 RTM

Ответы [ 4 ]

10 голосов
/ 10 декабря 2011

Если вы не возражаете против небольших взломов, это может помочь (только в 64-битном режиме, не проверено):

#include <windows.h>
#include <stdio.h>

unsigned char udiv128Data[] =
{
  0x48, 0x89, 0xD0, // mov rax,rdx
  0x48, 0x89, 0xCA, // mov rdx,rcx
  0x49, 0xF7, 0xF0, // div r8
  0x49, 0x89, 0x11, // mov [r9],rdx
  0xC3              // ret
};

unsigned char sdiv128Data[] =
{
  0x48, 0x89, 0xD0, // mov rax,rdx
  0x48, 0x89, 0xCA, // mov rdx,rcx
  0x49, 0xF7, 0xF8, // idiv r8
  0x49, 0x89, 0x11, // mov [r9],rdx
  0xC3              // ret
};

unsigned __int64 (__fastcall *udiv128)(unsigned __int64 numhi,
                                       unsigned __int64 numlo,
                                       unsigned __int64 den,
                                       unsigned __int64* rem) =
  (unsigned __int64 (__fastcall *)(unsigned __int64,
                                   unsigned __int64,
                                   unsigned __int64,
                                   unsigned __int64*))udiv128Data;

__int64 (__fastcall *sdiv128)(__int64 numhi,
                              __int64 numlo,
                              __int64 den,
                              __int64* rem) =
  (__int64 (__fastcall *)(__int64,
                          __int64,
                          __int64,
                          __int64*))sdiv128Data;

int main(void)
{
  DWORD dummy;
  unsigned __int64 ur;
  __int64 sr;
  VirtualProtect(udiv128Data, sizeof(udiv128Data), PAGE_EXECUTE_READWRITE, &dummy);
  VirtualProtect(sdiv128Data, sizeof(sdiv128Data), PAGE_EXECUTE_READWRITE, &dummy);
  printf("0x00000123456789ABCDEF000000000000 / 0x0001000000000000 = 0x%llX\n",
         udiv128(0x00000123456789AB, 0xCDEF000000000000, 0x0001000000000000, &ur));
  printf("-6 / -2 = %lld\n",
         sdiv128(-1, -6, -2, &sr));
  return 0;
}
6 голосов
/ 10 июля 2014

Небольшое улучшение - на одну инструкцию меньше

extern "C" digit64 udiv128(digit64 low, digit64 hi, digit64 divisor, digit64 *remainder);

; Arguments
; RCX       Low Digit
; RDX       High Digit
; R8        Divisor
; R9        *Remainder

; RAX       Quotient upon return

.code
udiv128 proc
    mov rax, rcx    ; Put the low digit in place (hi is already there)
    div r8      ; 128 bit divide rdx-rax/r8 = rdx remainder, rax quotient
    mov [r9], rdx   ; Save the reminder
    ret     ; Return the quotient
udiv128 endp
end
2 голосов
/ 08 мая 2019

Это доступно сейчас. Вы можете использовать _div128 и _udiv128

Свойство _div128 делит 128-разрядное целое число на 64-разрядное целое число. Возвращаемое значение содержит частное, а внутреннее возвращает остаток через параметр указателя. _div128 является специфическим для Microsoft.

В прошлом году было сказано, что он доступен с "Dev16" , но я не уверен, что это за версия. Я предполагаю, что это VS 16.0 A.K.A VS2019, но документация по MSDN показывает, что он идет дальше к VS2015

1 голос
/ 10 декабря 2011

Я не эксперт, но я выкопал это:

http://research.swtch.com/2008/01/division-via-multiplication.html

Интересные вещи. Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: Это тоже проницательный: http://www.gamedev.net/topic/508197-x64-div-intrinsic/

...