C++ 如何在 Visual Studio 上启用 __int128?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6759592/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to enable __int128 on Visual Studio?
提问by Amir Saniyan
When I type __int128
in a C++ project in Visual Studio, the editor changes color of __int128
to blue (like keyword).
当我__int128
在 Visual Studio 中输入 C++ 项目时,编辑器将颜色更改__int128
为蓝色(如关键字)。
But when I compile the source, the folowing error appears:
但是当我编译源代码时,出现以下错误:
error C4235:
nonstandard extension used : '__int128' keyword not supported on this architecture
How can I enable __int128
on Visual Studio?
如何__int128
在 Visual Studio 上启用?
采纳答案by Necrolis
MSDNdoesn't list it as being available, and this recent responseagrees, so officially, no, there is no type called __int128
and it can't be enabled.
MSDN没有将它列为可用,并且最近的这个回应同意,所以正式地,不,没有调用的类型__int128
并且它不能被启用。
Additionally, never trust the syntax hilighter; it is user editable, and thus likely to either have bogus or 'future' types in it. (it is probably a reserved word however, due to the error, thus you should avoid naming any types __int128
, this follows the convention that anything prefixed with a double underscore should reserved for compiler use).
此外,永远不要相信语法高亮器;它是用户可编辑的,因此可能包含虚假或“未来”类型。(但是,由于错误,它可能是一个保留字,因此您应该避免命名任何类型__int128
,这遵循以下约定,即任何以双下划线为前缀的内容都应保留供编译器使用)。
One would think the __int128
might be available on x64/IPF machines via register spanning, like __in64
is on 32bit targets, but right now the only128 bit types stem from SIMD types (__m128
and its various typed forms).
有人会认为它__int128
可能通过寄存器跨越在 x64/IPF 机器上可用,就像__in64
在 32 位目标上一样,但现在唯一的128 位类型源于 SIMD 类型(__m128
及其各种类型的形式)。
回答by Kermit the Frog
There is a new version of _int128 which solves some of the problems mentioned. It includes a natvis addin, so you can view int128 in the debugger. To do this it was nessecary to write an x86 version of int128, because natvis-dll's need to be win32. The idea of using af template for the members lo,hi is ok, but I think it's a little to optimistic, because the routines that do the real job have to use the CPU's registers which, at least at the moment, are only 64 bit. But ok when Intel releases a 128-bit CPU. in/out in c++ std stream are added A lot of inline operators have been added too, so the compiler will do
_int128 的新版本解决了提到的一些问题。它包含一个 natvis 插件,因此您可以在调试器中查看 int128。为此,必须编写 x86 版本的 int128,因为 natvis-dll 需要是 win32。为成员 lo,hi 使用 af 模板的想法是可以的,但我认为这有点乐观,因为真正起作用的例程必须使用 CPU 的寄存器,至少目前只有 64 位. 但是当英特尔发布 128 位 CPU 时就可以了。c++ std 流中的 in/out 添加了很多内联运算符也添加了,所以编译器会做
_int128 x = 10;
int y = 20;
_int128 z = x + y;
without ambiguities.
没有歧义。
The code is too big to fit in this answer so it's put in github with links to the files listet below
代码太大,无法放入此答案中,因此将其放在 github 中,并附有指向以下文件列表的链接
Int128x64.asm Assembler code for x64
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*(radix 10)
调试器调用的 AddIn-dll 将 _int128/_uint128 转换为 char*(基数 10)
回答by Kermit the Frog
I've found a treasure in my old Visual Studio 6.0 C++ from 1996 (32-bit) making use of MS's own assembler routines that enabled 64-bit math on a 32-bit CPU(__int64). Source-code unfortunately not available). However, doing a debug-session that calls these functions, copy/paste the disassembler-list, search-replace "dword ptr" -> "qword ptr", eax,ebx,... -> rax,rbx,... and a Little adjustment of registers used for parameter-passing (and a lot of coffee), I succeeded to make this code, that makes it possible to do _int128-math in x64-mode just as it is possible to do __int64-math with 32-bit. It's essential the same code, with a doubleup in bits/cycle. For the matter of copyrights, I've seen no licenses in the disassembler-list, and perhaps it's time for Microsoft to integrate this into their x64 C++ compiler (vers. 2015) The code goes here
我在 1996 年(32 位)的旧 Visual Studio 6.0 C++ 中发现了一个宝藏,利用 MS 自己的汇编程序在 32 位 CPU(__int64)上启用了 64 位数学。不幸的是,源代码不可用)。但是,执行调用这些函数的调试会话,复制/粘贴反汇编程序列表,搜索替换“dword ptr” -> “qword ptr”,eax,ebx,... -> rax,rbx,...和用于参数传递的寄存器的一些调整(和很多咖啡),我成功地制作了这段代码,这使得在 x64 模式下执行 _int128-math 成为可能,就像可以用 __int64-math 32 位。重要的是相同的代码,位/周期加倍。关于版权问题,我在反汇编列表中没有看到许可证,也许是
// 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, ©, &rhs);
return result;
}
inline _int128 operator%(const _int128 &rhs) const {
_int128 result, copy(*this);
int128rem(&result, ©, &rhs);
return result;
};
inline _int128 &operator+=(const _int128 &rhs) {
const _int128 copy(*this);
int128sum(this, ©, &rhs);
return *this;
}
inline _int128 &operator-=(const _int128 &rhs) {
const _int128 copy(*this);
int128dif(this, ©, &rhs);
return *this;
}
inline _int128 &operator*=(const _int128 &rhs) {
const _int128 copy(*this);
int128mul(this, ©, &rhs);
return *this;
}
inline _int128 &operator/=(const _int128 &rhs) {
const _int128 copy(*this);
int128div(this, ©, &rhs);
return *this;
}
inline _int128 &operator%=(const _int128 &rhs) {
const _int128 copy(*this);
int128rem(this, ©, &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, ©, &rhs);
return result;
}
inline _uint128 operator%(const _uint128 &rhs) const {
_uint128 result, copy(*this);
uint128rem(&result, ©, &rhs);
return result;
};
inline _uint128 &operator+=(const _uint128 &rhs) {
const _uint128 copy(*this);
int128sum(this, ©, &rhs);
return *this;
}
inline _uint128 &operator-=(const _uint128 &rhs) {
const _uint128 copy(*this);
int128dif(this, ©, &rhs);
return *this;
}
inline _uint128 &operator*=(const _uint128 &rhs) {
const _uint128 copy(*this);
int128mul(this, ©, &rhs);
return *this;
}
inline _uint128 &operator/=(const _uint128 &rhs) {
const _uint128 copy(*this);
uint128div(this, ©, &rhs);
return *this;
}
inline _uint128 &operator%=(const _uint128 &rhs) {
const _uint128 copy(*this);
uint128rem(this, ©, &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
There will be 3 more files. not enough Space here...
还会有 3 个文件。这里没有足够的空间...
回答by Kermit the Frog
And the rest is here. (conversion functions to/from string)
剩下的就在这里。(转换函数到/从字符串)
// 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
回答by BenGoldberg
Your conversions to/from string could use some improvement.
您与字符串之间的转换可能需要一些改进。
For saftey, the interface for converting to a string should include the allocated length of the user provided string, so you can return an error if they didn't provide enough memory.
为了安全起见,转换为字符串的接口应该包含用户提供的字符串的分配长度,因此如果它们没有提供足够的内存,您可以返回错误。
Also, try to process strings in chunks: for example, suppose the user wants to convert a 128 bit number into base 10. Instead of repeatedly doing modulo 10, you could be doing modulo 1000000000ul
, and using sprintf(s, "%09u", c)
.
此外,尝试分块处理字符串:例如,假设用户想要将 128 位数字转换为以 10 为基数的数字。而不是重复执行模 10,您可以执行 modulo 1000000000ul
,并使用sprintf(s, "%09u", c)
.
Converting from a string could be similarly optimized.
从字符串转换可以类似地优化。
It would not be a bad idea to include a divrem
method, with a return type of std::pair<_uint128, _uint128>
.
包含divrem
一个返回类型为std::pair<_uint128, _uint128>
.
It would be absolutely awesome if you had a integer class where the type used for hi
and lo
was a template parameter. Then, with a small handful of typedefs, you could create an int256, an int512, etc..
如果您有一个整数类,其中的类型用于hi
并且lo
是模板参数,那将是非常棒的。然后,使用少量 typedef,您可以创建一个 int256、一个 int512 等。