__int128时,编辑器会将__int128的颜色更改为蓝色(与关键字类似)。
但是,当我编译源代码时,出现以下错误:error C4235:
nonstandard extension used : '__int128' keyword not supported on this architecture
我如何在Visual Studio上启用__int128?
__int128时,编辑器会将__int128的颜色更改为蓝色(与关键字类似)。
但是,当我编译源代码时,出现以下错误:error C4235:
nonstandard extension used : '__int128' keyword not supported on this architecture
我如何在Visual Studio上启用__int128?
MSDN没有列出它作为可用类型,并且最近的反馈也表示,官方上说,没有名为__int128的类型并且不能启用。
此外,请不要完全信任语法高亮显示器;因为它是由用户编辑的,所以很可能包含虚假或'未来'的类型。 (它可能是一个保留词,但是由于这个错误,你应该避免给任何类型命名__int128,这遵循了任何以双下划线前缀的惯例都应该为编译器使用保留的规则)。
人们会认为,在x64/IPF机器上,__int128可能通过寄存器跨越而可用,就像在32位目标上的__in64一样,但现在唯一的128位类型源自SIMD类型(__m128及其各种类型形式)。
__int64,并且正如所述,它是一个保留字,但我还没有看到任何变更日志说明MSVC支持__int128。 - Necrolis我在1996年的Visual Studio 6.0 C++中发现了一项宝藏,利用微软自己的汇编例程在32位CPU(__int64)上实现了64位数学运算(源代码不可用)。然而,通过调试会话调用这些函数,复制/粘贴反汇编器列表,搜索替换 "dword ptr" -> "qword ptr",eax, ebx,... -> rax, rbx,...以及对用于参数传递的寄存器进行小的调整(并且喝了很多咖啡),我成功地将这个代码制作成了可以在x64模式下执行_int128数学运算的代码,就像在32位上执行__int64数学运算一样。这是基本相同的代码,每个周期增加了两倍的位数。关于版权问题,在反汇编器列表中我没有看到任何许可证,也许是时候让微软将其集成到他们的x64 C ++编译器(vers. 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, ©, &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
将会有3个新文件。这里的空间不够...
有一个新版本的_int128解决了一些问题。它包括natvis addin,因此您可以在调试器中查看int128。为此,需要编写x86版本的int128,因为natvis-dll需要win32。 使用成员lo、hi的模板的想法是可以的,但我认为这有点过于乐观,因为执行实际工作的例程必须使用CPU寄存器,而目前至少只有64位。但当英特尔发布128位CPU时就可以了。 在C++ std流中添加了in/out。 还添加了许多内联运算符,因此编译器将会做更多的优化。
_int128 x = 10;
int y = 20;
_int128 z = x + y;
没有歧义。
代码太大了,无法适应这个回答,因此放在github上,并附有下面列出的文件链接。
__int128 本地类型(类似于 GCC 中的 __int128),而不是 _int128 或第三方库,因为显然已经有大量的 bignum 库和关于它们的问题在这里。 - phuclv其余内容在此(字符串转换函数)
// 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
__MSVC_Int128.hpp实现了一个类,类似于__Int128,并且重载了运算符。然而,由于它是一个类,可能需要在某些地方进行类型转换。
它的名称是std:_Signed128或std:_Unsigned128,在使用之前需要检查头文件。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <__msvc_int128.hpp>
using namespace std;
using int128_t = _Unsigned128;
int128_t Gcd(int128_t a, int128_t b) {
int128_t r = a % b;
while (b > 0) {
a = r;
b = a;
a = r;
}
return a;
}
int128_t power(int128_t a, int n) {
if (n == 0)
return 1;
int128_t res = power(a, n / 2);
return (n % 2 == 0) ? res * res : res * res * a;
}
void write(int128_t x) {
if (x < 0)
x = -x, putchar('-');
if (x > 9)
write(x / 10);
putchar(int(x % (10) + '0'));
}
int main() { write(power(2, 64)); }
Gcd()函数对大多数输入都不会终止。嗯,而且它也没有被引用...要删除吗? - undefined另一种选择是使用boost: https://www.boost.org/doc/libs/1_62_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints/cpp_int.html
你的字符串转换功能还有提升空间。
为了安全起见,将字符串转换包含用户提供字符串的分配长度的接口,这样如果他们没有提供足够的内存,你就可以返回一个错误。
另外,尝试按块来处理字符串:例如,假设用户想要将128位数字转换为10进制。 你可以使用模 1000000000ul 来代替重复的模10,并使用 sprintf(s,"%09u",c)。
从字符串转换也可以进行类似的优化。
如果你包括一个带有返回类型为 std::pair<_uint128, _uint128> 的 divrem 方法,那将不是一个坏主意。
如果你有一个整数类,其中用于 hi 和 lo 的类型是一个模板参数,那将非常棒。然后,通过一小堆 typedef,你可以创建int256、int512等。