Подтвердить что ты не робот

Как включить __int128 в Visual Studio?

Когда я набираю __int128 в проекте С++ в Visual Studio, редактор меняет цвет __int128 на синий (например, ключевое слово).

Но когда я компилирую источник, появляется следующая ошибка:

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

Как включить __int128 в Visual Studio?

4b9b3361

Ответ 1

MSDN не перечисляет его как доступный, и этот недавний ответ согласен, так что официально, нет, нет типа с именем __int128 и он не может быть включен.

Кроме того, никогда не доверяйте синтаксису; он может редактироваться пользователем и, следовательно, может содержать либо фиктивные, либо "будущие" типы. (однако, возможно, это зарезервированное слово из-за ошибки, поэтому следует избегать именования любых типов __int128, это следует соглашению, согласно которому все, что начинается с двойного подчеркивания, должно быть зарезервировано для использования компилятором).

Можно было бы подумать, что __int128 может быть доступен на компьютерах x64/IPF с помощью __in64 регистра, как __in64 для 32- __in64 целей, но сейчас только 128-битные типы происходят из типов SIMD (__m128 и его различных типизированных форм).

Ответ 2

Существует новая версия _int128, которая решает некоторые из упомянутых проблем. Он включает в себя добавление natvis, поэтому вы можете просматривать int128 в отладчике. Для этого было необязательно писать x86-версию int128, потому что natvis-dll должен быть win32. Идея использования шаблона af для членов lo, привет в порядке, но я думаю, что это немного оптимистично, потому что подпрограммы, которые выполняют настоящую работу, должны использовать Регистры CPU, которые, по крайней мере, на данный момент, всего 64 бит. Но хорошо, когда Intel выпускает 128-битный процессор. in/out в С++ поток std добавлен Также добавлено много встроенных операторов, поэтому компилятор выполнит

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

без двусмысленностей.

Код слишком велик, чтобы вписаться в этот ответ, поэтому он помещает github со ссылками на список файлов ниже

Новый заголовок Int128.h

Int128x64.asm Ассемблерный код для x64

Int128x86.cpp

Int128Str.cpp Общий для x86 и x64

Int128IO.cpp Общий для x86 и x64

AddIn-dll, вызываемый отладчиком для преобразования _int128/_uint128 в char * (radix 10)

Заголовок для всех natvis addin dll

Ответ 3

Я нашел сокровище в своей старой Visual Studio 6.0 С++ с 1996 года (32-разрядная версия) с использованием собственных ассемблерных процедур MS, которые включали 64-битную математику на 32-разрядном процессоре (__ int64). Исходный код, к сожалению, недоступен). Тем не менее, выполнение отладочной сессии, которая вызывает эти функции, копирует/вставляет список дизассемблера, заменяет "dword ptr" → "qword ptr", eax, ebx,... → rax, rbx,... и небольшая настройка регистров, используемых для передачи параметров (и большого количества кофе), мне удалось сделать этот код, что позволяет делать _int128-math в x64-режиме, как это возможно сделать __int64-math с 32-битный. Это необходимо для того же кода, с удвоением в битах/циклах. Что касается авторских прав, я не видел никаких лицензий в списке дизассемблера и, возможно, настало время для того, чтобы Microsoft интегрировала это в свой компилятор x64 С++ (версия 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

Ваши преобразования в/из строки могут использовать некоторое улучшение.

Для saftey интерфейс для преобразования в строку должен включать выделенную длину предоставленной пользователем строки, поэтому вы можете вернуть ошибку, если они не предоставили достаточно памяти.

Кроме того, попробуйте обработать строки в кусках: например, предположим, что пользователь хочет преобразовать 128-битное число в базу 10. Вместо того, чтобы многократно выполнять modulo 10, вы можете делать modulo 1000000000ul и использовать sprintf(s, "%09u", c).

Преобразование из строки может быть аналогичным образом оптимизировано.

Неплохо было бы включить метод divrem с возвращаемым типом std::pair<_uint128, _uint128>.

Было бы замечательно, если бы у вас был целочисленный класс, где тип, используемый для hi и lo, был параметром шаблона. Затем, с небольшой горсткой typedefs, вы можете создать int256, int512 и т.д.