12

Visual C++ には本当に 128 ビット除算の組み込み関数がないのでしょうか?

と呼ばれる 64x64=128 ビットの乗算組み込み関数があり、これはx64 アセンブラー命令_umul128()とうまく一致します。MUL

当然のことながら、128/64=64 ビットの除算組み込み (DIV命令のモデル化) もあると思いましたが、驚いたことに、Visual C++ も Intel C++ もそれを持っていないようで、少なくとも intrin.h にはリストされていません。

誰かがそれを確認できますか?コンパイラの実行ファイルの関数名をgrepしてみましたが、そもそも見つからなかっ_umul128たので、探し方を間違えたのでしょう。

更新: 少なくともumul128、Visual C++ 2010 の c1.dll でパターン (先頭のアンダースコアなし) を見つけました。他のすべての組み込み関数はその周りにリストされていますが、残念ながら「udiv128」などはありません:(それを実装することを「忘れて」います。

明確にするために:私は128ビットのデータ型を探しているだけでなく、C++で128ビットのスカラーintを64ビットのintで割る方法も探しています。組み込み関数またはネイティブの128 ビット整数サポートのいずれかが問題を解決します。

編集:答えはノーです_udiv128。Visual Studio 2010 から 2017 までの組み込み関数はありませんが、Visual Studio 2019 RTM で利用できます。

4

5 に答える 5

12

少しのハックを気にしない場合は、これが役立つ場合があります (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;
}
于 2011-12-10T12:07:39.943 に答える
7

小さな改善 - 命令が 1 つ減る

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
于 2014-07-09T23:06:46.370 に答える
2

私は専門家ではありませんが、これを掘り起こしました:

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

面白いもの。それが役に立てば幸い。

編集:これも洞察に満ちています:http ://www.gamedev.net/topic/508197-x64-div-intrinsic/

于 2011-12-10T00:05:04.727 に答える