【问题标题】:How to enable __int128 on Visual Studio?如何在 Visual Studio 上启用 __int128?
【发布时间】:2011-10-09 05:32:07
【问题描述】:

当我在 Visual Studio 的 C++ 项目中键入 __int128 时,编辑器会将 __int128 的颜色更改为蓝色(类似于关键字)。

但是当我编译源码时,出现以下错误:

error C4235: 
nonstandard extension used : '__int128' keyword not supported on this architecture

如何在 Visual Studio 上启用__int128

【问题讨论】:

  • 你的平台是什么? 64 位?
  • 我用x86、x64和安腾编译过,但是还是有错误。
  • 嗯,你的架构不支持它。
  • 您是在问如何摆脱警告/错误,以便您可以自己使用该标识符,它定义它,还是您在问如何使用该名称的现有标识符,这似乎未定义?
  • 您可以使用_umul128 使您自己成为您自己的,至少对于乘法而言。

标签: c++ visual-studio int128


【解决方案1】:

MSDN 并没有将其列为可用,而最近的response 同意,所以正式地说,不,没有称为__int128 的类型,并且无法启用。

此外,永远不要相信语法提示符;它是用户可编辑的,因此可能包含虚假或“未来”类型。 (它可能是一个保留字,但是由于错误,因此您应该避免命名任何类型 __int128,这遵循任何以双下划线为前缀的内容都应保留供编译器使用的约定。

有人会认为 __int128 可能通过寄存器跨越在 x64/IPF 机器上可用,例如 __in64 用于 32 位目标,但目前只有 128 位类型源自 SIMD 类型(__m128 及其各种类型的表单)。

【讨论】:

  • @LưuVĩnhPhúc:这看起来像一个文档错误,如果您查看侧面菜单,您会注意到它只列出了 __int64,并且如上所述,它是一个保留字,但我'还没有看到说明 MSVC 支持 __int128 的更改日志。
  • 抱歉,没看过其他版本。但既然已经被引入到文档中,也许他们会在未来的某个时间实施
  • @LưuVĩnhPhúc:它多年来一直在词法分析器和语法高亮显示中,但 MS 根据“客户需求”设计他们的编译器,到目前为止还没有客户推动实现这一点(以下标准也是如此,虽然 Herb Sutter 为使 MSVC C++11 兼容付出了很多努力,但谁知道我们会在 MSVC 2014/15/16 中看到它?)。
  • VS2013 和 VS2015 的 MSDN 文档都在基本类型 (C++) 页面中列出了 __int128。早期版本没有。我只有 2012 年,所以我无法验证实际支持。这只是 2013 年的一次提及,因此很可能是文档错误。 2015 在多个地方都有它,所以如果它不受支持,他们会更认真地考虑它。左侧导航菜单上没有版本。
  • MSDN 官方更新了 VS2015 的页面,声明不支持 __int128。 msdn.microsoft.com/en-us/library/cc953fe1.aspx
【解决方案2】:

有一个新版本的 _int128 解决了上面提到的一些问题。它包含一个 natvis 插件,因此您可以在调试器中查看 int128。为此,必须编写 x86 版本的 int128,因为 natvis-dll 需要是 win32。 成员 lo,hi 使用 af 模板的想法是可以的,但我认为这有点过于乐观,因为做真正工作的套路必须使用 CPU 的寄存器,至少目前只有 64 位。但是当英特尔发布 128 位 CPU 时就可以了。 添加了 c++ std 流中的输入/输出 还添加了很多内联运算符,所以编译器会这样做

_int128 x = 10;
int y = 20;
_int128 z = x + y;

没有歧义。

代码太大,无法容纳此答案,因此将其放在 github 中,并带有指向下面文件列表的链接

New header Int128.h

Int128x64.asm Assembler code for x64

Int128x86.cpp

Int128Str.cpp Common for x86 and x64

Int128IO.cpp Common for x86 and x64

AddIn-dll called by debugger to convert _int128/_uint128 to char*(decimal/hex)

Header for all natvis addin dll's

【讨论】:

  • OP 询问了 MSVC 的 __int128 native 类型(如 GCC 中的 __int128),而不是 _int128 而不是第 3 方库,因为显然这里已经有大量的 bignum 库和很多关于它们的问题。
  • 有人下载过这些单元吗?存储库不知何故完全消失了。
【解决方案3】:

我在 1996 年的旧 Visual Studio 6.0 C++(32 位)中发现了一个宝藏,它利用了 MS 自己的汇编程序,在 32 位 CPU (__int64) 上启用了 64 位数学。不幸的是,源代码不可用)。 但是,执行调用这些函数的调试会话,复制/粘贴反汇编程序列表,搜索替换“dword ptr”->“qword ptr”,eax,ebx,... -> rax,rbx,...和用于参数传递的寄存器的一点调整(和很多咖啡),我成功地制作了这段代码,这使得在 x64 模式下执行 _int128-math 成为可能,就像可以使用 __int64-math 一样32 位。相同的代码是必不可少的,位/周期翻倍。 关于版权问题,我在反汇编程序列表中没有看到任何许可证,也许是时候让微软将其集成到他们的 x64 C++ 编译器(2015 版)中了 代码在这里

// File:Int128.h
#pragma once

#include "PragmaLib.h" // contains #pragma comment(lib,"Yourlib.lib")

#ifndef _M_X64

#error Int128 is available only in x64 arhcitecture

#else

class _int128;
class _uint128;
extern "C" {    
  void int128sum( void *dst, const void *x, const void *y);
  void int128dif( void *dst, const void *x, const void *y);
  void int128mul( void *dst, const void *x, const void *y);
  void int128div( void *dst, const void *x, const void *y);
  void int128rem( void *dst, const void *x, const void *y);
  void int128neg( void *dst, const void *x);
  int  int128cmp(const void *n1, const void *n2);
  void uint128div( void *dst, const void *x, const void *y);
  void uint128rem( void *dst, const void *x, const void *y);
  int  uint128cmp(const void *n1, const void *n2);
};

class _int128 {
private:
  _int128(unsigned __int64 _lo, const unsigned __int64 _hi) : lo(_lo), hi(_hi) {
  }
public:
  unsigned __int64 lo;
  unsigned __int64 hi;

  inline _int128() {
  }
  inline _int128(unsigned __int64 n) : lo(n), hi(0) {
  }
  inline _int128(__int64 n) : lo(n), hi(n>=0)?0:-1) { // remember signextend hi if n < 0 (2-complement)
  }
  inline _int128(unsigned int n) : lo(n), hi(0) {
  }
  inline _int128(int n) : lo(n), hi(n>=0)?0:-1) {
  }
  inline _int128(unsigned short n) : lo(n), hi(0) {
  }
  inline _int128(short n) : lo(n), hi(n>=0)?0:-1) {
  }
  explicit _int128(const char *str);

  operator unsigned __int64() const {
    return lo;
  }
  operator __int64() const {
    return lo;
  }
  operator unsigned int() const {
    return (unsigned int)lo;
  }
  operator int() const {
    return (int)lo;
  }
  inline _int128 operator+(const _int128 &rhs) const {
    _int128 result;
    int128sum(&result, this, &rhs);
    return result;
  }

  inline _int128 operator-(const _int128 &rhs) const {
    _int128 result;
    int128dif(&result, this, &rhs);
    return result;
  }

  inline _int128 operator-() const {
    _int128 result;
    int128neg(&result, this);
    return result;
  }
  inline _int128 operator*(const _int128 &rhs) const {
    _int128 result;
    int128mul(&result, this, &rhs);
    return result;
  }

  inline _int128 operator/(const _int128 &rhs) const {
    _int128 result, copy(*this);
    int128div(&result, &copy, &rhs);
    return result;
  }
  inline _int128 operator%(const _int128 &rhs) const {
    _int128 result, copy(*this);
    int128rem(&result, &copy, &rhs);
    return result;
  };

  inline _int128 &operator+=(const _int128 &rhs) {
    const _int128 copy(*this);
    int128sum(this, &copy, &rhs);
    return *this;
  }
  inline _int128 &operator-=(const _int128 &rhs) {
    const _int128 copy(*this);
    int128dif(this, &copy, &rhs);
    return *this;
  }
  inline _int128 &operator*=(const _int128 &rhs) {
    const _int128 copy(*this);
    int128mul(this, &copy, &rhs);
    return *this;
  }
  inline _int128 &operator/=(const _int128 &rhs) {
    const _int128 copy(*this);
    int128div(this, &copy, &rhs);
    return *this;
  }
  inline _int128 &operator%=(const _int128 &rhs) {
    const _int128 copy(*this);
    int128rem(this, &copy, &rhs);
    return *this;
  }

  inline _int128 operator&(const _int128 &rhs) const {
    return _int128(lo&rhs.lo, hi&rhs.hi);
  }
  inline _int128 operator|(const _int128 &rhs) const {
    return _int128(lo|rhs.lo, hi|rhs.hi);
  }
  inline _int128 operator^(const _int128 &rhs) const {
    return _int128(lo^rhs.lo, hi^rhs.hi);
  }

  const char *parseDec(const char *str); // return pointer to char following the number
  const char *parseHex(const char *str); // do
  const char *parseOct(const char *str); // do
};

class _uint128 {
public:
  unsigned __int64 lo;
  unsigned __int64 hi;

  inline _uint128() {
  }
  inline _uint128(const _int128 &n) : lo(n.lo), hi(n.hi) {
  }
  inline _uint128(unsigned __int64 n) : lo(n), hi(0) {
  }
  inline _uint128(__int64 n) : lo(n), hi(n>=0)?0:-1) {
  }
  inline _uint128(unsigned int n) : lo(n), hi(0) {
  }
  inline _uint128(int n) : lo(n), hi(n>=0)?0:-1) {
  }
  inline _uint128(unsigned short n) : lo(n), hi(0) {
  }
  inline _uint128(short n) : lo(n), hi(n>=0)?0:-1) {
  }
  explicit _uint128(const char *str);

  inline operator _int128() const {
    return *(_int128*)(void*)this;
  }
  inline operator unsigned __int64() const {
    return lo;
  }
  inline operator __int64() const {
    return lo;
  }
  inline operator unsigned int() const {
    return (unsigned int)lo;
  }
  inline operator int() const {
    return (int)lo;
  }

  inline _uint128 operator+(const _uint128 &rhs) const {
    _uint128 result;
    int128sum(&result, this, &rhs);
    return result;
  }

  inline _uint128 operator-(const _uint128 &rhs) const {
    _uint128 result;
    int128dif(&result, this, &rhs);
    return result;
  }

  inline _uint128 operator*(const _uint128 &rhs) const {
    _uint128 result;
    int128mul(&result, this, &rhs);
    return result;
  }

  inline _uint128 operator/(const _uint128 &rhs) const {
    _uint128 result, copy(*this);
    uint128div(&result, &copy, &rhs);
    return result;
  }

  inline _uint128 operator%(const _uint128 &rhs) const {
    _uint128 result, copy(*this);
    uint128rem(&result, &copy, &rhs);
    return result;
  };

  inline _uint128 &operator+=(const _uint128 &rhs) {
    const _uint128 copy(*this);
    int128sum(this, &copy, &rhs);
    return *this;
  }
  inline _uint128 &operator-=(const _uint128 &rhs) {
    const _uint128 copy(*this);
    int128dif(this, &copy, &rhs);
    return *this;
  }
  inline _uint128 &operator*=(const _uint128 &rhs) {
    const _uint128 copy(*this);
    int128mul(this, &copy, &rhs);
    return *this;
  }
  inline _uint128 &operator/=(const _uint128 &rhs) {
    const _uint128 copy(*this);
    uint128div(this, &copy, &rhs);
    return *this;
  }
  inline _uint128 &operator%=(const _uint128 &rhs) {
    const _uint128 copy(*this);
    uint128rem(this, &copy, &rhs);
    return *this;
  }
  const char *parseDec(const char *str); // return pointer to char following the number
  const char *parseHex(const char *str); // do
  const char *parseOct(const char *str); // do

};

inline bool operator==(const _int128 &lft, const _int128 &rhs) {
  return (lft.lo == rhs.lo) && (lft.hi == rhs.hi);
}
inline bool operator==(const _int128 &lft, const _uint128 &rhs) {
  return (lft.lo == rhs.lo) && (lft.hi == rhs.hi);
}
inline bool operator==(const _uint128 &lft, const _int128 &rhs) {
  return (lft.lo == rhs.lo) && (lft.hi == rhs.hi);
}
inline bool operator==(const _uint128 &lft, const _uint128 &rhs) {
  return (lft.lo == rhs.lo) && (lft.hi == rhs.hi);
}
inline bool operator!=(const _int128 &lft, const _int128 &rhs) {
  return (lft.lo != rhs.lo) || (lft.hi != rhs.hi);
}
inline bool operator!=(const _int128 &lft, const _uint128 &rhs) {
  return (lft.lo != rhs.lo) || (lft.hi != rhs.hi);
}
inline bool operator!=(const _uint128 &lft, const _int128 &rhs) {
  return (lft.lo != rhs.lo) || (lft.hi != rhs.hi);
}
inline bool operator!=(const _uint128 &lft, const _uint128 &rhs) {
  return (lft.lo != rhs.lo) || (lft.hi != rhs.hi);
}

inline bool operator>(const _int128 &lft, const _int128 &rhs) {
  return int128cmp(&lft, &rhs) > 0;
}
inline bool operator>(const _int128 &lft, const _uint128 &rhs) {
  return uint128cmp(&lft, &rhs) > 0;
}
inline bool operator>(const _uint128 &lft, const _int128 &rhs) {
  return uint128cmp(&lft, &rhs) > 0;
}
inline bool operator>(const _uint128 &lft, const _uint128 &rhs) {
  return uint128cmp(&lft, &rhs) > 0;
}

inline bool operator>=(const _int128 &lft, const _int128 &rhs) {
  return int128cmp(&lft, &rhs) >= 0;
}
inline bool operator>=(const _int128 &lft, const _uint128 &rhs) {
  return uint128cmp(&lft, &rhs) >= 0;
}
inline bool operator>=(const _uint128 &lft, const _int128 &rhs) {
  return uint128cmp(&lft, &rhs) >= 0;
}
inline bool operator>=(const _uint128 &lft, const _uint128 &rhs) {
  return uint128cmp(&lft, &rhs) >= 0;
}

inline bool operator<(const _int128 &lft, const _int128 &rhs) {
  return int128cmp(&lft, &rhs) < 0;
}
inline bool operator<(const _int128 &lft, const _uint128 &rhs) {
  return uint128cmp(&lft, &rhs) < 0;
}
inline bool operator<(const _uint128 &lft, const _int128 &rhs) {
  return uint128cmp(&lft, &rhs) < 0;
}
inline bool operator<(const _uint128 &lft, const _uint128 &rhs) {
  return uint128cmp(&lft, &rhs) < 0;
}

inline bool operator<=(const _int128 &lft, const _int128 &rhs) {
  return int128cmp(&lft, &rhs) <= 0;
}
inline bool operator<=(const _int128 &lft, const _uint128 &rhs) {
  return uint128cmp(&lft, &rhs) <= 0;
}
inline bool operator<=(const _uint128 &lft, const _int128 &rhs) {
  return uint128cmp(&lft, &rhs) <= 0;
}
inline bool operator<=(const _uint128 &lft, const _uint128 &rhs) {
  return uint128cmp(&lft, &rhs) <= 0;
}

char    * _i128toa(_int128 value, char *str, int radix);
char    * _ui128toa(_uint128 value, char *str, int radix);
wchar_t * _i128tow(_int128 value, wchar_t *str, int radix);
wchar_t * _ui128tow(_uint128 value, wchar_t *str, int radix);

inline char radixLetter(unsigned int c) {
  return (c < 10) ? ('0' + c) : ('a' + (c-10));
}

inline wchar_t wradixLetter(unsigned int c) {
  return (c < 10) ? ('0' + c) : ('a' + (c-10));
}

inline bool isodigit(unsigned char ch) {
  return ('0' <= ch) && (ch < '8');
}

unsigned int convertNumberChar(char digit);

#endif // _M_X64

; File: Int128x64.asm
; build obj-file with
; ml64 /nologo /c /Zf /Fo$(IntDir)Int128x64.obj Int128x64.asm
.CODE

;void int128sum(_int128 &dst, cnost _int128 &x, const _int128 &y);
int128sum PROC
    push    rbx
    mov     rax, qword ptr[rdx]
    add     rax, qword ptr[r8]
    mov     rbx, qword ptr[rdx+8]
    adc     rbx, qword ptr[r8+8]
    mov     qword ptr[rcx], rax
    mov     qword ptr[rcx+8], rbx
    pop     rbx
    ret
int128sum ENDP

;void int128dif( _int128 &dst, const _int128 &x, const _int128 &y);
int128dif PROC
    push    rbx
    mov     rax, qword ptr[rdx]
    sub     rax, qword ptr[r8]
    mov     rbx, qword ptr[rdx+8]
    sbb     rbx, qword ptr[r8+8]
    mov     qword ptr[rcx]  , rax
    mov     qword ptr[rcx+8], rbx
    pop     rbx
    ret
int128dif ENDP

;void int128mul(_int128 &dst, const _int128 &x, const _int128 &y);
int128mul PROC
    push    rbx
    mov     rax, qword ptr[rdx+8]           ; rax = x.hi
    mov     rbx, qword ptr[r8+8]            ; rbx = y.hi
    or      rbx, rax                        ; rbx = x.hi | y.hi
    mov     rbx, qword ptr[r8]              ; rbx = y.lo
    jne     Hard                            ; if(x.hi|y.hi) goto Hard
                                            ; simple int64 multiplication
    mov     rax, qword ptr[rdx]             ; rax = x.lo
    mul     rbx                             ; rdx:rax = rax * rbx
    mov     qword ptr[rcx]  , rax           ; dst.lo = rax
    mov     qword ptr[rcx+8], rdx           ; dst.hi = rdx
    pop     rbx
    ret
Hard:                                       ; assume rax = x.hi, rbx = y.lo
    push    rsi
    mov     rsi, rdx                        ; need rdx for highend of mul, so rsi=&x
    mul     rbx                             ; rdx:rax = x.hi * y.lo
    mov     r9 , rax                        ; 
    mov     rax, qword ptr[rsi]             ; rax     = x.lo
    mul     qword ptr[r8+8]                 ; rdx:rax = x.lo * y.hi
    add     r9, rax                         ; r9      = lo(x.hi*y.lo+x.lo*y.hi); 
    mov     rax, qword ptr[rsi]             ; rax     = x.lo
    mul     rbx                             ; rdx:rax = x.lo * y.lo
    add     rdx, r9
    mov     qword ptr[rcx]  , rax
    mov     qword ptr[rcx+8], rdx
    pop     rsi
    pop     rbx
    ret
int128mul ENDP


;void int128div(_int128 &dst, const _int128 &x, const _int128 &y);
int128div PROC
    push        rdi
    push        rsi
    push        rbx
    push        rcx
    mov         r9,  rdx
    xor         rdi, rdi
    mov         rax, qword ptr[r9+8]
    or          rax, rax
    jge         L1
    inc         rdi
    mov         rdx, qword ptr[r9]
    neg         rax
    neg         rdx
    sbb         rax, 0
    mov         qword ptr[r9+8], rax
    mov         qword ptr[r9], rdx
L1:
    mov         rax, qword ptr[r8+8]
    or          rax, rax
    jge         L2
    inc         rdi
    mov         rdx, qword ptr[r8]
    neg         rax
    neg         rdx
    sbb         rax,0
    mov         qword ptr[r8+8], rax
    mov         qword ptr[r8], rdx
L2:
    or          rax, rax
    jne         L3
    mov         rcx, qword ptr[r8]
    mov         rax, qword ptr[r9+8]
    xor         rdx, rdx
    div         rcx
    mov         rbx, rax
    mov         rax, qword ptr[r9]
    div         rcx
    mov         rdx, rbx
    jmp         L4
L3:
    mov         rbx,rax
    mov         rcx,qword ptr[r8]
    mov         rdx,qword ptr[r9+8]
    mov         rax,qword ptr[r9]
L5:
    shr         rbx, 1
    rcr         rcx, 1
    shr         rdx, 1
    rcr         rax, 1
    or          rbx, rbx
    jne         L5
    div         rcx
    mov         rsi, rax
    mul         qword ptr[r8+8]
    mov         rcx, rax
    mov         rax, qword ptr[r8]
    mul         rsi
    add         rdx, rcx
    jb          L6
    cmp         rdx, qword ptr[r9+8]
    ja          L6
    jb          L7
    cmp         rax, qword ptr[rdx]
    jbe         L7
L6:
    dec         rsi
L7:
    xor         rdx, rdx
    mov         rax, rsi
L4:
    dec         rdi
    jne         L8
    neg         rdx
    neg         rax
    sbb         rdx, 0
L8:
    pop         rcx
    pop         rbx
    pop         rsi
    pop         rdi
    mov         qword ptr[rcx], rax
    mov         qword ptr[rcx+8], rdx
    ret
int128div ENDP

;void int128rem( _int128 &dst, const _int128 &x, const _int128 &y);
int128rem PROC
    push        rbx
    push        rdi
    push        rcx
    mov         r9,  rdx
    xor         rdi, rdi
    mov         rax, qword ptr[r9+8]
    or          rax, rax
    jge         L1
    inc         rdi
    mov         rdx, qword ptr[r9]
    neg         rax
    neg         rdx
    sbb         rax, 0
    mov         qword ptr[r9+8], rax
    mov         qword ptr[r9], rdx
L1:
    mov         rax, qword ptr[r8+8]
    or          rax, rax
    jge         L2
    mov         rdx, qword ptr[r8]
    neg         rax
    neg         rdx
    sbb         rax, 0
    mov         qword ptr[r8+8], rax
    mov         qword ptr[r8], rdx
L2:
    or          rax, rax
    jne         L3
    mov         rcx, qword ptr[r8]
    mov         rax, qword ptr[r9+8]
    xor         rdx, rdx
    div         rcx
    mov         rax, qword ptr[r9]
    div         rcx
    mov         rax, rdx
    xor         rdx, rdx
    dec         rdi
    jns         L4
    jmp         L8
L3:
    mov         rbx, rax
    mov         rcx, qword ptr[r8]
    mov         rdx, qword ptr[r9+8]
    mov         rax, qword ptr[r9]
L5:
    shr         rbx, 1
    rcr         rcx, 1
    shr         rdx, 1
    rcr         rax, 1
    or          rbx, rbx
    jne         L5
    div         rcx
    mov         rcx, rax
    mul         qword ptr[r8+8]
    xchg        rax, rcx
    mul         qword ptr[r8]
    add         rdx, rcx
    jb          L6
    cmp         rdx, qword ptr[r9+8]
    ja          L6
    jb          L7
    cmp         rax, qword ptr[r9]
    jbe         L7
L6:
    sub         rax, qword ptr[r8]
    sbb         rdx, qword ptr[r8+8]
L7:
    sub         rax, qword ptr[r9]
    sbb         rdx, qword ptr[r9+8]
    dec         rdi
    jns         L8
L4:
    neg         rdx
    neg         rax
    sbb         rdx, 0
L8:
    pop         rcx
    pop         rdi
    pop         rbx
    mov         qword ptr[rcx], rax
    mov         qword ptr[rcx+8], rdx
    ret
int128rem ENDP

;void int128neg( _int128 &dst, const _int128 &x);
int128neg PROC
    mov         rax,qword ptr[rdx]
    neg         rax
    mov         r8, qword ptr[rdx+8]
    adc         r8, 0
    neg         r8
    mov         qword ptr[rcx], rax
    mov         qword ptr[rcx+8], r8
    ret
int128neg ENDP

;int int128cmp(const _int128 &n1, const _int128 &n2);
int128cmp PROC
    mov         rax, qword ptr[rcx+8]       ; n1.hi
    cmp         rax, qword ptr[rdx+8]       ; n2.hi
    jl          lessthan                            ; signed compare of n1.hi and n2.hi
    jg          greaterthan
    mov         rax, qword ptr[rcx]         ; n2.lo
    cmp         rax, qword ptr[rdx]         ; n2.lo
    jb          lessthan                    ; unsigned compare of n1.lo and n2.lo
    ja          greaterthan
    mov         rax, 0                      ; they are equal
    ret
greaterthan:
    mov         rax, 1
    ret
lessthan:
    mov         rax, -1
    ret
int128cmp ENDP

END

; File:UInt128x64.asm
; build obj-file with
; ml64 /nologo /c /Zf /Fo$(IntDir)UInt128x64.obj UInt128x64.asm

.CODE

;void uint128div(_uint128 &dst, const _uint128 &x, const _uint128 &y);
uint128div PROC
    push        rbx
    push        rsi
    push        rcx
    mov         r9, rdx
    mov         rax, qword ptr[r8+8]
    or          rax, rax
    jne         L1
    mov         rcx, qword ptr[r8]
    mov         rax, qword ptr[r9+8]
    xor         rdx, rdx
    div         rcx
    mov         rbx, rax
    mov         rax, qword ptr[r9]
    div         rcx
    mov         rdx, rbx
    jmp         L2
L1:
    mov         rcx, rax
    mov         rbx, qword ptr[r8]
    mov         rdx, qword ptr[r9+8]
    mov         rax, qword ptr[r9]
L3:
    shr         rcx, 1
    rcr         rbx, 1
    shr         rdx, 1
    rcr         rax, 1
    or          rcx, rcx
    jne         L3
    div         rbx
    mov         rsi, rax
    mul         qword ptr[r8+8]
    mov         rcx, rax
    mov         rax, qword ptr[r8]
    mul         rsi
    add         rdx, rcx
    jb          L4
    cmp         rdx, qword ptr[r9+8]
    ja          L4
    jb          L5
    cmp         rax, qword ptr[r9]
    jbe         L5
L4:
    dec         rsi
L5:
    xor         rdx, rdx
    mov         rax, rsi
L2:
    pop         rcx
    pop         rsi
    pop         rbx
    mov         qword ptr[rcx], rax
    mov         qword ptr[rcx+8], rdx
    ret
uint128div ENDP

;void uint128rem(_uint128 &dst, const _uint128 &x, const _uint128 &y);
uint128rem PROC
    push        rbx
    push        rcx
    mov         r9, rdx
    mov         rax, qword ptr[r8+8]
    or          rax, rax
    jne         L1
    mov         rcx, qword ptr[r8]
    mov         rax, qword ptr[r9+8]
    xor         rdx, rdx
    div         rcx
    mov         rax, qword ptr[r9]
    div         rcx
    mov         rax, rdx
    xor         rdx, rdx
    jmp         L2
L1:
    mov         rcx, rax
    mov         rbx, qword ptr[r8]
    mov         rdx, qword ptr[r9+8]
    mov         rax, qword ptr[r9]
L3:
    shr         rcx, 1
    rcr         rbx, 1
    shr         rdx, 1
    rcr         rax, 1
    or          rcx, rcx
    jne         L3
    div         rbx
    mov         rcx, rax
    mul         qword ptr[r8+8]
    xchg        rax, rcx
    mul         qword ptr[r8]
    add         rdx, rcx
    jb          L4
    cmp         rdx, qword ptr[r9+8]
    ja          L4
    jb          L5
    cmp         rax, qword ptr[r9]
    jbe         L5
L4:
    sub         rax, qword ptr[r8]
    sbb         rdx, qword ptr[r8+8]
L5:
    sub         rax, qword ptr[r9]
    sbb         rdx, qword ptr[r9+8]
    neg         rdx
    neg         rax
    sbb         rdx, 0
L2:
    pop         rcx
    pop         rbx
    mov         qword ptr[rcx], rax
    mov         qword ptr[rcx+8], rdx
    ret
uint128rem ENDP

;int uint128cmp(const _uint128 &n1, const _uint128 &n2);
uint128cmp PROC
    mov         rax, qword ptr[rcx+8]       ; n1.hi
    cmp         rax, qword ptr[rdx+8]       ; n2.hi
    jb          lessthan                    ; usigned compare of n1.hi and n2.hi
    ja          greaterthan
    mov         rax, qword ptr[rcx]         ; n2.lo
    cmp         rax, qword ptr[rdx]         ; n2.lo
    jb          lessthan                    ; unsigned compare of n1.lo and n2.lo
    ja          greaterthan
    mov         rax, 0                      ; they are equal
    ret
greaterthan:
    mov         rax, 1
    ret
lessthan:
    mov         rax, -1
    ret
uint128cmp ENDP

END

还有 3 个文件。这里没有足够的空间......

【讨论】:

    【解决方案4】:

    其余的都在这里。 (转换函数到/从字符串)

    // File:Int128IOx64.cpp
    #include "pch.h"
    
    #ifdef _M_X64
    
    #include <Math/Int128.h>
    
    static const _int128 _0(0);
    static const _int128 _10(10);
    static const _int128 _16(16);
    static const _int128 _8(16);
    
    char *_i128toa(_int128 value, char *str, int radix) {
      assert(radix >= 2 && radix <= 36);
      char *s = str;
      const bool negative = value < _0;
      if (negative && (radix == 10)) {
        value = -value;
        while (value != _0) {
          const unsigned int c = value % _10;
          *(s++) = radixLetter(c);
          value /= _10;
        }
        *(s++) = '-';
        *s = 0;
        return _strrev(str);
      }
    
      _uint128 v(value);
      const _uint128 r(radix);
      while (v != _0) {
        const unsigned int c = v % r;
        *(s++) = radixLetter(c);
        v /= r;
      }
      if (s == str) {
        return strcpy(str, "0");
      }
      else {
        *s = 0;
        return _strrev(str);
      }
      return str;
    }
    
    wchar_t *_i128tow(_int128 value, wchar_t *str, int radix) {
      wchar_t *s = str;
      const bool negative = value < _0;
      if (negative && (radix == 10)) {
        value = -value;
        while (value != _0) {
          const unsigned int c = value % _10;
          *(s++) = wradixLetter(c);
          value /= _10;
        }
        *(s++) = '-';
        *s = 0;
        return _wcsrev(str);
      }
    
      _uint128 v(value);
      const _uint128 r(radix);
      while (v != _0) {
        const unsigned int c = v % r;
        *(s++) = radixLetter(c);
        v /= r;
      }
      if (s == str) {
        return wcscpy(str, L"0");
      }
      else {
        *s = 0;
        return _wcsrev(str);
      }
      return str;
    }
    
    const char *_int128::parseDec(const char *str) { // return pointer to char following the number
      bool negative = false;
      bool gotDigit = false;
      switch (*str) {
      case '+':
        str++;
        break;
      case '-':
        str++;
        negative = true;
      }
      *this = _0;
      while (isdigit(*str)) {
        gotDigit = true;
        const unsigned int d = *(str++) - '0';
        *this *= _10;
        *this += d;
      }
      if (!gotDigit) {
        throw "_int128:string is not a number";
      }
      if (negative) {
        *this = -*this;
      }
      return str;
    }
    
    const char *_int128::parseHex(const char *str) {
      *this = 0;
      while (isxdigit(*str)) {
        const unsigned int d = convertNumberChar(*(str++));
        *this *= _16;
        *this += d;
      }
      return str;
    }
    
    const char *_int128::parseOct(const char *str) {
      *this = 0;
      while (isodigit(*str)) {
        const unsigned int d = convertNumberChar(*(str++));
        *this *= _8;
        *this += d;
      }
      return str;
    }
    
    _int128::_int128(const char *str) {
      if (*str == '-') {
        parseDec(str);
      } else {
        if (!isdigit(*str)) {
          throw exception("_int128:string is not an integer");
        }
        if (*str == '0') {
          switch (str[1]) {
          case 'x':
            parseHex(str + 2);
            break;
          case 0:
            *this = 0;
            break;
          default:
            parseOct(str + 1);
          }
        }
        else {
          parseDec(str);
        }
      }
    }
    #endif // _M_X64
    
    
    // File:UInt128IOx64.cpp
    #include "pch.h"
    
    #ifdef _M_X64
    
    #include <Math/Int128.h>
    
    static const _uint128 _0(0);
    static const _uint128 _10(10);
    static const _uint128 _16(16);
    static const _uint128 _8(16);
    
    char*_ui128toa(_uint128 value, char *str, int radix) {
      assert(radix >= 2 && radix <= 36);
      char *s = str;
      const _uint128 r(radix);
      while (value != _0) {
        const unsigned int c = value % r;
        *(s++) = radixLetter(c);
        value /= r;
      }
      if (s == str) {
        return strcpy(str, "0");
      }
      else {
        *s = 0;
        return _strrev(str);
      }
    }
    
    wchar_t *_ui128tow(_uint128 value, wchar_t *str, int radix) {
      assert(radix >= 2 && radix <= 36);
      wchar_t *s = str;
      const _uint128 r(radix);
      while (value != _0) {
        const unsigned int c = value % r;
        *(s++) = wradixLetter(c);
        value /= r;
      }
      if (s == str) {
        return wcscpy(str, L"0");
      }
      else {
        *s = 0;
        return _wcsrev(str);
      }
    }
    
    const char *_uint128::parseDec(const char *str) {
      *this = 0;
      while (isdigit(*str)) {
        const unsigned int d = *(str++) - '0';
        *this *= _10;
        *this += d;
      }
      return str;
    }
    
    const char *_uint128::parseHex(const char *str) {
      *this = 0;
      while (isxdigit(*str)) {
        const unsigned int d = convertNumberChar(*(str++));
        *this *= _16;
        *this += d;
      }
      return str;
    }
    
    const char *_uint128::parseOct(const char *str) {
      *this = 0;
      while (isodigit(*str)) {
        const unsigned int d = convertNumberChar(*(str++));
        *this *= _8;
        *this += d;
      }
      return str;
    }
    
    _uint128::_uint128(const char *str) {
      if (!isdigit(*str)) {
        throw exception("_uint128:string is not an integer");
      }
      if (*str == '0') {
        switch (str[1]) {
        case 'x':
          parseHex(str + 2);
          break;
        case 0:
          *this = 0;
          break;
        default:
          parseOct(str + 1);
          break;
        }
      }
      else {
        parseDec(str);
      }
    }
    
    #endif // _M_X64
    
    // File:Int128IOCommon.cpp
    #include "pch.h"
    
    #ifdef _M_X64
    
    #include <Math/Int128.h>
    
    unsigned int convertNumberChar(char digit) {
      switch(digit) {
      case '0': return 0;
      case '1': return 1;
      case '2': return 2;
      case '3': return 3;
      case '4': return 4;
      case '5': return 5;
      case '6': return 6;
      case '7': return 7;
      case '8': return 8;
      case '9': return 9;
      case 'a':
      case 'A': return 10;
      case 'b':
      case 'B': return 11;
      case 'c':
      case 'C': return 12;
      case 'd':
      case 'D': return 13;
      case 'e':
      case 'E': return 14;
      case 'f':
      case 'F': return 15;
      default :
        return 0;
      }
    }
    
    #endif // _M_X64
    

    【讨论】:

      【解决方案5】:

      【讨论】:

      • 它非常慢,至少在 32 位机器上。
      【解决方案6】:

      您与字符串的转换可能需要一些改进。

      为了安全起见,转换为字符串的接口应该包含用户提供的字符串的分配长度,因此如果它们没有提供足够的内存,您可以返回错误。

      另外,尝试以块的形式处理字符串:例如,假设用户想要将 128 位数字转换为以 10 为底的数字。您可以使用 sprintf(s, "%09u", c),而不是重复模 10,而是模 1000000000ul .

      从字符串转换可以进行类似的优化。

      包含divrem 方法并返回类型为std::pair&lt;_uint128, _uint128&gt; 并不是一个坏主意。

      如果你有一个整数类,其中用于hilo 的类型是模板参数,那将是非常棒的。然后,使用少量 typedef,您可以创建一个 int256、一个 int512 等。

      【讨论】:

      • 您是要评论@KermittheFrog 的答案之一吗?
      猜你喜欢
      • 1970-01-01
      • 2015-06-04
      • 2013-04-19
      • 1970-01-01
      • 1970-01-01
      • 2021-05-15
      • 2019-10-18
      • 1970-01-01
      相关资源
      最近更新 更多