BigNumberByLeo/Src/Base/Uint.mqh
Nique_372 a5dfc36bdc
2026-09-26 20:59:30 -05:00

2062 lines
56 KiB
MQL5

//+------------------------------------------------------------------+
//| Main.mqh |
//| Copyright 2026, Niquel Mendoza |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Niquel Mendoza"
#property link "https://www.mql5.com"
#property strict
#ifndef BIGNUMBERSBYLEO_SRC_BASE_UINT_MQH
#define BIGNUMBERSBYLEO_SRC_BASE_UINT_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "Common.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// maximo numero a represetar = 2^31-1 (INT MAX) elementos * 64bits = 137438953408 este es el maximo numero de bits
// que peude tener un numero dado que un array como maximo tamaño dtiene INT_MAX elementos no peude tener mas
// y como cada elemtnos es un uint64_t entonces se peude repenstart ese numero * 64 bits
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// ahora mismo usaremos el contructor normal
// dado que siempre itera al menos 1 vez
#define BigUintegerConstCheck(v, vs) BigUInteger(v, vs)
//+------------------------------------------------------------------+
//| Clase biguinteger |
//+------------------------------------------------------------------+
struct BigUInteger : public BigIBase
{
public:
//--- Constructores
//--- tomando prestado
BigUInteger(ulong& v[], const int vs_8);
BigUInteger(const int vs_8, ulong& v[]);
//-- valor
BigUInteger(const ulong number, int reserve);
BigUInteger(ENUM_BIGNUMBERBYLEO_STR_BASE base, const string& str);
//-- desde bytes
BigUInteger(const uchar& bytes[], int byteorder);
//-- reserva \ default
BigUInteger(int initial_reserve);
BigUInteger();
//--- unitarios
//-- Negacion
BigUInteger operator~() const;
//--- bit simples
//-- and
void operator&=(const BigUInteger& b);
BigUInteger operator&(const BigUInteger& b) const;
__forceinline ulong operator&(const ulong b) const;
//-- or
void operator|=(const BigUInteger& b);
BigUInteger operator|(const BigUInteger& b) const;
BigUInteger operator|(const ulong b) const;
//-- xor
void operator^=(const BigUInteger& b);
BigUInteger operator^(const BigUInteger& b) const;
BigUInteger operator^(const ulong b) const;
//-- dezplazamientos
// left
__forceinline void operator<<=(const ulong b) { UShiftLeft(b); }
BigUInteger operator<<(const ulong b) const;
// right
void operator>>=(const ulong b);
BigUInteger operator>>(const ulong b) const;
//---- aritmeticos
//- suma
void operator+=(const BigUInteger& b);
BigUInteger operator+(const BigUInteger& b) const;
void operator+=(const ulong b);
BigUInteger operator+(const ulong b) const;
//- resta
void operator-=(const BigUInteger& b);
BigUInteger operator-(const BigUInteger& b) const;
void operator-=(const ulong b);
BigUInteger operator-(const ulong b) const;
//- mul
void operator*=(const BigUInteger& b);
BigUInteger operator*(const BigUInteger& b) const;
void operator*=(const ulong b);
BigUInteger operator*(const ulong b) const;
//- div or mod
// vs otro b completo
template <typename TOp>
void DivModInPlace(BigUInteger& b);
//- div
// nota no es const BigUInteger& b dado que como tal NO modificamso b
// solo que nos tomoamos prestado su array para lectura noma...
__forceinline void operator/=(BigUInteger& b);
BigUInteger operator/(BigUInteger& b) const;
void operator/=(const ulong b);
BigUInteger operator/(const ulong b) const;
//- mod
__forceinline void operator%=(BigUInteger& b);
BigUInteger operator%(BigUInteger& b) const;
void operator%=(const ulong b);
ulong operator%(const ulong b) const;
//--- compracion
__forceinline int Cmp(const BigIBase& b) const { return CmpInt<BigUInteger>(b); }
//-- basicas
// big
bool operator>(const BigUInteger& b) const;
bool operator>=(const BigUInteger& b) const;
bool operator==(const BigUInteger& b) const;
// normal
__forceinline bool operator>(const ulong b) const { return m_v_s > 1 || (m_v[0] > b) ; }
__forceinline bool operator>=(const ulong b) const { return m_v_s > 1 || (m_v[0] >= b); }
__forceinline bool operator==(const ulong b) const { return m_v_s > 1 || (m_v[0] == b); }
//-- derivadas
// big
__forceinline bool operator!=(const BigUInteger& b) const { return !(this == b); }
__forceinline bool operator<(const BigUInteger& b) const { return !(this >= b); }
__forceinline bool operator<=(const BigUInteger& b) const { return !(this > b); }
// normal
__forceinline bool operator!=(const ulong b) const { return !(this == b); }
__forceinline bool operator<(const ulong b) const { return !(this >= b); }
__forceinline bool operator<=(const ulong b) const { return !(this > b); }
//--- complejos
// this = base
// e = exp (long)
// n = (mod n)
void PowMod(const ulong e, const BigUInteger& n);
void PowMod(const BigUInteger& e, const BigUInteger &n);
// Es probasblemnete un primo?¿
template <typename TRandom>
bool IsProbablePrime(int rounds) const;
// GCD Maximo comun divisor normal
// = gdc(this, v) (retrona ulong)
ulong Gdc(const ulong v) const;
//--- From \ LLenar
// dataos ranodm (llena en unr ango menor a other)
template <typename TRandom>
__forceinline void FillRandomRange(const BigUInteger& other);
// desde bytes
void FromBytesLE(const uchar& buf[]);
void FromBytesBE(const uchar& buf[]);
// de otro (swap robando buffer)
__forceinline void RobarDe(BigUInteger& other);
// formato DER (tag) (len) (Content)
int FromDER(const uchar& buf[], int r);
//--- Utilidades
//--- To (converiones)
//- bytes
// NOTA: retornan el tamaño final (no cuanto escribieron.. exactamente)
int ToBytesLE(uchar& buf[], int w = 0, int k = BIGUINTEGER_TOBYTES_DEFAULTK) const;
int ToBytesBE(uchar& buf[], int w = 0, int k = BIGUINTEGER_TOBYTES_DEFAULTK) const;
//- DER Format
// k=numero de bytes a esceribir
// wlen=byte de esvritua de len
// is_high_encinado=marca si el mas alto qeu tiene dato tiene el bti 7 encenidod (para el 0x0)
int DerEstimateLen(bool& is_high_encendido, int& k, uchar& lenw) const;
//-- string
int ToString(uchar& buf[]) const;
//----
static __forceinline int AbsS(int v) { return v; }
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/* xor\or
a ^ 0 = a
{
1 ^ 0 = 1 (en caso sea 1 entonces 1 dado que son difente)
0 ^ 0 = 0 (en caso sea 0 ambos iguales 0 igual)
ambos casos se conerva
}
a | 0 = a
Lo mismo daod que añades 0 nada
aparte
1 | 0 = 1
0 | 0 = 0
*/
//+------------------------------------------------------------------+
//| Constructores |
//+------------------------------------------------------------------+
BigUInteger::BigUInteger(ulong &v[], const int vs_8)
: BigIBase(v, vs_8)
{
}
//+------------------------------------------------------------------+
BigUInteger::BigUInteger(const int vs_8, ulong& v[])
: BigIBase(vs_8, v)
{
}
//+------------------------------------------------------------------+
BigUInteger::BigUInteger(const ulong number, int reserve)
: BigIBase(number, reserve)
{
}
//+------------------------------------------------------------------+
BigUInteger::BigUInteger(int initial_reserve)
: BigIBase(initial_reserve)
{
}
//+------------------------------------------------------------------+
BigUInteger::BigUInteger()
: BigIBase()
{
}
//+------------------------------------------------------------------+
//| Propios contructors |
//+------------------------------------------------------------------+
BigUInteger::BigUInteger(ENUM_BIGNUMBERBYLEO_STR_BASE base, const string& str)
{
//---
m_v_s = BIGNUMERBYLEO_INITIAL_SIZE_ZERO;
//---
const int digtis = g_tsn_biguinteger_base_max[base];
if(digtis < 0)
{
// En caso de error lo inciamos como 0
ArrayResize(m_v, BIGNUMERBYLEO_INITIAL_RESERVE, BIGNUMERBYLEO_INITIAL_RESERVE);
m_v[0] = 0ULL;
return;
}
//---
const int l = StringLen(str);
const int req = l << 1;
if(ArraySize(m_v) < req) // no hay tamaño suficiente
ArrayResize(m_v, req, req);
m_v[0] = 0ULL;
//---
int i = 0;
while(i < l)
{
const int take = (l - i < digtis) ? (l - i) : digtis;
ulong chunk_val = 0;
ulong chunk_pow = 1;
//---
for(int k = 0; k < take; k++)
{
chunk_val = chunk_val * base + (str[i++] ^ '0');
chunk_pow *= base;
}
//---
this *= chunk_pow; // desplaza lo acumulado por la potencia correcta
this += chunk_val; // suma el chunk nuevo
}
}
//+------------------------------------------------------------------+
BigUInteger::BigUInteger(const uchar &bytes[], int byteorder)
: BigIBase()
{
if(byteorder == BIGUINTEGER_LOADBYTES_BE)
FromBytesBE(bytes);
else
FromBytesLE(bytes);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template <typename TRandom>
__forceinline void BigUInteger::FillRandomRange(const BigUInteger& other)
{
m_v_s = other.m_v_s;
TRandom::RandomUlongArrRange(m_v, m_v_s, other[m_v_s - 1]);
}
// n_menos2
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BigUInteger::FromBytesLE(const uchar& buf[])
{
//---
const int k = ArraySize(buf);
if(k > ArraySize(m_v))
ArrayResize(m_v, k, k);
//---
int j;
CNumberUtils::ULL_LoadFromBytesLE(k, m_v, m_v_s, buf, j);
//--- Limpiamos zeros altos..
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS(m_v, m_v_s)
}
//+------------------------------------------------------------------+
// La idea es leer desde el byte[0] (mas significativo) a menos significativo
// lo demas el armado es igual
void BigUInteger::FromBytesBE(const uchar& buf[])
{
//---
const int k = ArraySize(buf);
if(k > ArraySize(m_v))
ArrayResize(m_v, k, k);
//---
int j;
CNumberUtils::ULL_LoadFromBytesBE(k, m_v, m_v_s, buf, j);
//--- Limpiamos zeros altos..
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS(m_v, m_v_s)
}
//+------------------------------------------------------------------+
//| DER Functions |
//+------------------------------------------------------------------+
int BigUInteger::FromDER(const uchar &buf[], int r)
{
//--- tag
if(buf[r++] != CBL_ASN1_TAG_INTEGER) // tag integer
return -1; // invalido
//--- len
int t = buf[r++];
if((t & CBL_ASN1_MASK_BYTEALTO) != 0)
{
//---
const int lr = r;
t &= CBL_ASN1_MASK_CLEAN_BYTEALTO;
//---
// Ahora de aqui puieden venir 127 bytes que peuden representar unnumero enorme
// Pero como tal?¿ en MQL5 una array de ulongs max size= INT_MAX
// Transofmrado a bytes 17K Mill aprox... asi que seria un numero en bin tal que
// 0100 0000 0000 0000 0000 0000 0000 0000 0000
// algo de 36 bits de numero que caben en un ulong osea solo podemos leer algo de 5 bytes aprox (4.5)
r += t; // numero de bytes del numero
//---
t = 0;
// quizas meter un guard mas k<32 ahi ya se deitne pro qeu no tendira mas sentido?¿
// seguir leyendo bytes dado que pare mpar buf no peude tener mas lenght que eso... (int)
for(int i = r - 1, k = 0; i >= lr && k < 32; i--, k += 8)
{
t |= int(buf[i]) << k;
}
// listo ya tenemos el numero de bytes.. ahora..
}
/* con la convencion entonces si se peude represnetar el 0...
else
if(t == 1 && buf[r] == 0) // 2 pos es 0 entonces mvs 0
{
BIGNUMBERBYLEO_ZERO
return ++r;
}*/
// tal cual sin nada..
// ahora r apunta al byte justo a leer
const int lr = r;
//------ Ahora toca leer el numero en si
//---
const int sob = t & 7; // % 8 cuantos sobraan
const int blocks = t - sob; // Cuantos bloques enteros procesaremos
// bloque=byte (mal nomrbe quizas)
//--- Ahora si (leemos como BE)
const int fr = r + blocks;
r = fr - 1;
m_v_s = 0;
// bloques completos
for(; r >= lr;)
{
//--- write
m_v[m_v_s++] = ulong(buf[r--]) |
ulong(buf[r--]) << 8 |
ulong(buf[r--]) << 16 |
ulong(buf[r--]) << 24 |
ulong(buf[r--]) << 32 |
ulong(buf[r--]) << 40 |
ulong(buf[r--]) << 48 |
ulong(buf[r--]) << 56;
}
// en caso haya sobrante
if(sob)
{
r = lr + (sob - 1);
m_v[m_v_s] = 0ULL;
for(int j = 0; j < (sob << 3); j += 8)
m_v[m_v_s] |= ulong(buf[r--]) << j;
m_v_s++;
}
//---
return fr; // hasta donde leimos (nueva posicion para leer)
}
//+------------------------------------------------------------------+
int BigUInteger::DerEstimateLen(bool& is_high_encendido, int& k, uchar& lenw) const
{
//---
if(BIGNUMERBYLEO_UINTEGER_IZ_ZERO)
{
k = 1;
is_high_encendido = false;
lenw = 1; // 1+0
return 3;
}
//---
const int vs_bytes = (m_v_s << 3); // en bytes
const ulong high = m_v[m_v_s - 1]; // alto
const int clz = CBitTricks::CLZ(high); // clz
k = vs_bytes - (clz >> 3); // k
is_high_encendido = (uchar(high >> (((63 - clz) >> 3) << 3)) & 0x80) != 0; // alto encendido
const int number_len_size = is_high_encendido + k; // el len del numero en si
//--- calculo del len (final)
uchar count = 1;
if(number_len_size > 127)
{
int l = number_len_size;
// en cuantos bytes reqeurrimos (extra)
do
{
l >>= 8;
count++;
}
while(l > 0);
lenw = CBL_ASN1_MASK_BYTEALTO | count;
}
else
{
lenw = uchar(number_len_size);
}
//--- final retornamso todo lo que estiamso para el der
return 1 + count + number_len_size;
}
//+------------------------------------------------------------------+
#define BIGUINTEGERBYLEO_DER_WRITE(buf, w, num, is_high_encendido, k, lenw, total) \
{ \
buf[w++] = CBL_ASN1_TAG_INTEGER; \
CBL_ASN1_U_WRITELEN(buf, w, lenw, total) \
if(is_high_encendido) \
buf[w++] = 0x00; \
const int blocks = k >> 3; \
const int sob = k & 7; \
int r = blocks - 1; \
for(; r >= 0; r--) \
{ \
const ulong v = num[r]; \
buf[w++] = uchar(v >> 56); \
buf[w++] = uchar(v >> 48); \
buf[w++] = uchar(v >> 40); \
buf[w++] = uchar(v >> 32); \
buf[w++] = uchar(v >> 24); \
buf[w++] = uchar(v >> 16); \
buf[w++] = uchar(v >> 8); \
buf[w++] = uchar(v); \
} \
if(sob) \
{ \
r++; \
const ulong v = num[r]; \
for(int j = ((sob << 3) - 8); j >= 0; j -= 8) \
buf[w++] = uchar(v >> j); \
} \
}
//+------------------------------------------------------------------+
//| To Bytes |
//+------------------------------------------------------------------+
int BigUInteger::ToBytesLE(uchar &buf[], int w = 0, int k = BIGUINTEGER_TOBYTES_DEFAULTK) const
{
//---
const int vs_bytes = (m_v_s << 3);
if(k == BIGUINTEGER_TOBYTES_DEFAULTK)
k = vs_bytes;
else
if(k == BIGUINTEGER_TOBYTES_EXACTK)
{
// en este caso -2 exacto miramos el mas alto
// y en base a eso reducimos
k = vs_bytes - (CBitTricks::CLZ(m_v[m_v_s - 1]) >> 3);
}
//---
if(k + w > ArraySize(buf))
ArrayResize(buf, k + w);
//---
int ksob = k - vs_bytes; // cuantos bytes sobrrana (padding)
//---
int blocks, sob;
if(ksob <= 0) // menor o igual a lo que tenemos
{
blocks = k >> 3; // Cuantos bloques enteros procesaremos
sob = k & 7; // % 8 cuantos sobraan
}
else // en este caso hay que agregar padding calculs con el max (usamos sin sob)
{
blocks = m_v_s;
sob = 0;
}
//--- Ahora si
int r = 0;
// bloques completos
for(; r < blocks; r++)
{
const ulong v = m_v[r];
//--- write
buf[w++] = uchar(v);
buf[w++] = uchar(v >> 8);
buf[w++] = uchar(v >> 16);
buf[w++] = uchar(v >> 24);
buf[w++] = uchar(v >> 32);
buf[w++] = uchar(v >> 40);
buf[w++] = uchar(v >> 48);
buf[w++] = uchar(v >> 56);
}
// en caso haya sobrante
if(sob)
{
const ulong v = m_v[r];
for(int j = 0; j < (sob << 3); j += 8)
buf[w++] = uchar(v >> j);
}
//--- Padding de zeros al final
if(ksob > 0) // hay sobrante
{
ksob += w; // fin
for(; w < ksob; w++)
buf[w] = 0;
}
//---
return w;
}
//+------------------------------------------------------------------+
int BigUInteger::ToBytesBE(uchar &buf[], int w = 0, int k = -1) const
{
//---
const int vs_bytes = (m_v_s << 3);
if(k == BIGUINTEGER_TOBYTES_DEFAULTK)
k = vs_bytes;
else
if(k == BIGUINTEGER_TOBYTES_EXACTK)
{
// en este caso -2 exacto miramos el mas alto
// y en base a eso reducimos
k = vs_bytes - (CBitTricks::CLZ(m_v[m_v_s - 1]) >> 3);
}
//---
if(k + w > ArraySize(buf))
ArrayResize(buf, k + w);
//---
int ksob = k - vs_bytes; // cuantos bytes sobrrana (padding)
//---
int blocks, sob;
if(ksob <= 0) // menor o igual a lo que tenemos
{
blocks = k >> 3; // Cuantos bloques enteros procesaremos
sob = k & 7; // % 8 cuantos sobraan
}
else // en este caso hay que agregar padding calculs con el max (usamos sin sob)
{
blocks = m_v_s;
sob = 0;
}
//---
int r = blocks - 1;
//--- Padding de zeros al inicio
if(ksob > 0) // hay sobrante
{
ksob += w;
for(; w < ksob; w++)
buf[w] = 0;
}
//--- Ahora si
// bloques completos
for(; r >= 0; r--)
{
const ulong v = m_v[r];
//--- write
buf[w++] = uchar(v >> 56);
buf[w++] = uchar(v >> 48);
buf[w++] = uchar(v >> 40);
buf[w++] = uchar(v >> 32);
buf[w++] = uchar(v >> 24);
buf[w++] = uchar(v >> 16);
buf[w++] = uchar(v >> 8);
buf[w++] = uchar(v);
}
// en caso haya sobrante
if(sob)
{
r++;
const ulong v = m_v[r];
for(int j = ((sob << 3) - 8); j >= 0; j -= 8)
buf[w++] = uchar(v >> j);
}
//---
return w;
}
//+------------------------------------------------------------------+
//| To Str |
//+------------------------------------------------------------------+
int BigUInteger::ToString(uchar& buf[]) const
{
//--- Contamos digitos de todos
// cada bit es un digito
int n = 0;
for(int i = m_v_s - 1; i >= 0; i--)
{
ulong v = m_v[i];
while(v)
{
v /= 10ULL;
n++;
}
}
//---
const int fn = ArrayResize(buf, n);
Print(n);
n--; // ahora baja
//--- To integer
for(int i = m_v_s - 1; i >= 0; i--)
{
ulong uvalue = m_v[i];
//---
while(uvalue >= 100)
{
const ulong idx = (uvalue % 100ULL) << 1ULL;
buf[n--] = g_tsn_digit_pairs[idx + 1];
buf[n--] = g_tsn_digit_pairs[idx];
uvalue /= 100ULL;
}
//---
if(uvalue >= 10)
{
const ulong idx = (uvalue << 1ULL);
buf[n--] = g_tsn_digit_pairs[idx + 1];
buf[n--] = g_tsn_digit_pairs[idx];
}
else
{
buf[n--] = uchar('0' + uvalue);
}
}
return fn;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BigUInteger::operator>(const BigUInteger& b) const
{
if(m_v_s != b.m_v_s)
return m_v_s > b.m_v_s; // quien es mayor
// en caso de que sean iguales
for(int i = m_v_s - 1; i >= 0; i--)
{
if(m_v[i] != b.m_v[i]) // no coindice
return m_v[i] > b.m_v[i];
}
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BigUInteger::operator>=(const BigUInteger& b) const
{
if(m_v_s != b.m_v_s)
return m_v_s >= b.m_v_s; // quien es mayor o igual
// en caso de que sean iguales
for(int i = m_v_s - 1; i >= 0; i--)
{
if(m_v[i] != b.m_v[i]) // en caso no sean iguales
return m_v[i] > b.m_v[i];
}
// son iguales
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BigUInteger::operator==(const BigUInteger& b) const
{
if(m_v_s != b.m_v_s)
return false;
for(int i = m_v_s - 1; i >= 0; i--)
{
if(m_v[i] != b.m_v[i])
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| neg bit |
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator~() const
{
ulong v[];
ArrayResize(v, m_v_s);
for(int i = 0; i < m_v_s; i++)
v[i] = ~m_v[i];
return BigUintegerConstCheck(v, m_v_s);
}
//+------------------------------------------------------------------+
//| and |
//+------------------------------------------------------------------+
void BigUInteger::operator&=(const BigUInteger& b)
{
if(b.m_v_s < m_v_s)
{
// b es menor lo qeu se nos aplica es menor [1][0] &= [2]
m_v_s = b.m_v_s; // lo bajamos
}
//---
for(int i = 0; i < m_v_s; i++)
m_v[i] &= b.m_v[i];
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator&(const BigUInteger& b) const
{
//---
ulong v[];
const int vs = BIGNUMERBYLEO_MIN(b.m_v_s, m_v_s);
//---
ArrayResize(v, vs);
//---
for(int i = 0; i < vs; i++)
v[i] = m_v[i] & b.m_v[i];
//---
return BigUintegerConstCheck(v, vs);
}
//+------------------------------------------------------------------+
__forceinline ulong BigUInteger::operator&(const ulong b) const
{
return m_v[0] & b;
}
//+------------------------------------------------------------------+
//| or |
//+------------------------------------------------------------------+
void BigUInteger::operator|=(const BigUInteger& b)
{
if(m_v_s > b.m_v_s) // this es mayor
{
for(int i = 0; i < b.m_v_s; i++) // hasta donde de
m_v[i] |= b.m_v[i];
}
else // b es mayor
{
// [1][0] |= [1][1][1]
int i = 0;
for(; i < m_v_s; i++)
m_v[i] |= b.m_v[i];
//---
m_v_s = b.m_v_s; // ahora del mismo tamaño
// chekeo dado que incilate peude no tener el mismo tamao (reservas impliciatas)
// que se hacen
if(ArraySize(m_v) < m_v_s)
ArrayResize(m_v, m_v_s, m_v_s);
//--- el resto copy directo (a|0=a)
ArrayCopy(m_v, b.m_v, i, i, m_v_s);
}
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator|(const BigUInteger& b) const
{
//---
ulong v[];
int vs;
//---
if(m_v_s > b.m_v_s) // this es mayor
{
vs = m_v_s;
ArrayResize(v, vs);
int i = 0;
// hasta terminar con b
for(; i < b.m_v_s; i++)
v[i] = m_v[i] | b.m_v[i];
// resto
for(; i < vs; i++)
v[i] = m_v[i];
}
else // b es mayor
{
vs = b.m_v_s;
ArrayResize(v, vs);
int i = 0;
// terminar con this
for(; i < m_v_s; i++)
v[i] = m_v[i] | b.m_v[i];
// resto
ArrayCopy(v, b.m_v, i, i, vs);
}
//---
return BigUintegerConstCheck(v, vs);
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator|(const ulong b) const
{
//---
ulong v[];
ArrayResize(v, m_v_s);
v[0] = m_v[0] | b;
ArrayCopy(v, m_v, 1, 1, m_v_s);
//---
return BigUintegerConstCheck(v, m_v_s);
}
//+------------------------------------------------------------------+
//| xor |
//+------------------------------------------------------------------+
void BigUInteger::operator^=(const BigUInteger& b)
{
if(m_v_s > b.m_v_s) // this es mayor
{
for(int i = 0; i < b.m_v_s; i++) // hasta donde de
m_v[i] ^= b.m_v[i];
}
else // b es mayor
{
// [1][0] ^= [1][1][1]
int i = 0;
for(; i < m_v_s; i++)
m_v[i] ^= b.m_v[i];
//---
m_v_s = b.m_v_s; // ahora del mismo tamaño
// chekeo dado que incilate peude no tener el mismo tamao (reservas impliciatas)
// que se hacen
if(ArraySize(m_v) < m_v_s)
ArrayResize(m_v, m_v_s, m_v_s);
//--- el resto copy directo (a^0=a)
ArrayCopy(m_v, b.m_v, i, i, m_v_s);
}
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator^(const BigUInteger& b) const
{
//---
ulong v[];
int vs;
//---
if(m_v_s > b.m_v_s) // this es mayor
{
vs = m_v_s;
ArrayResize(v, vs);
int i = 0;
// hasta terminar con b
for(; i < b.m_v_s; i++)
v[i] = m_v[i] ^ b.m_v[i];
// resto
for(; i < vs; i++)
v[i] = m_v[i];
}
else // b es mayor
{
vs = b.m_v_s;
ArrayResize(v, vs);
int i = 0;
// terminar con this
for(; i < m_v_s; i++)
v[i] = m_v[i] ^ b.m_v[i];
// resto
ArrayCopy(v, b.m_v, i, i, vs);
}
//---
return BigUintegerConstCheck(v, vs);
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator^(const ulong b) const
{
//--- hay data alemnos 1
ulong v[];
ArrayResize(v, m_v_s);
v[0] = m_v[0] ^ b;
ArrayCopy(v, m_v, 1, 1, m_v_s);
//---
return BigUintegerConstCheck(v, m_v_s);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// crea uno nuevo
BigUInteger BigUInteger::operator<<(const ulong b) const
{
//--- chekeamos 0 dado que 0<<x con x grande peude hacer crecer el tamaño artificilaemtne de mvs
if(BIGNUMERBYLEO_UINTEGER_IZ_ZERO)
return BigUInteger(0ULL, 1);
//---
const int els = int(b >> 6); // b / 64
const int els_sob = int(b & 63); // % 64
//---
ulong v[];
int vs = m_v_s;
//---
if(els_sob == 0) // exacto
{
//---
vs += els;
ArrayResize(v, vs);
//---
int i = vs - 1;
for(; i >= els; i--)
v[i] = m_v[i - els];
//---
for(; i >= 0; i--)
v[i] = 0ULL;
//---
return BigUInteger(v, vs);
}
//---
int r = vs - 1; // read pointer
const int srh = (64 - els_sob); // shr
ulong hi = m_v[r]; // valor de lectura actual hi
const ulong overflow = hi >> srh; // si los altos habia valor randeo del dhift en adelante
//---
vs += els;
int w = vs - 1; // escritura en els-1 (depende de que tantos salots elsb haya)
if(overflow)
{
vs++;
ArrayResize(v, vs);
v[vs - 1] = overflow;
}
else
{
ArrayResize(v, vs);
}
//--- iter
while(r > 0)
{
const ulong prev = m_v[--r]; // valor previo
v[w--] = (hi << els_sob) | (prev >> srh); // (valor alto dezplaado) | (valor bajo overflow siguiente)
hi = prev; // ahora el alto es nuestro prev (Curr)
}
v[w] = hi << els_sob; // terminos con el valor 0 o ultimo
//---
return BigUInteger(v, vs);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/*
[..[..]] [[..]..]
>> ..
entonces
[....] [[..][..]]
en (m_v[el_sh_b] >> el_sh); tomtamos el 0 y lo demplzamosmo
[[..]..] a [..[..]]
toca rellenar altos del +1
ahi entra y (que ahora mismo apunta al=1)
y que da [[..][..]]
pero slk = 2 asi que l aisuinte iuteacion ya no se da (2<2 = false)
*/
//+------------------------------------------------------------------+
void BigUInteger::operator>>=(const ulong b)
{
//--- neceistamos chekear dado que si size=1 pero "jalamos" 1 entonces queda en 0 (no peude ser 0 el size)
const int el_sh_b = int(b >> 6);
if(el_sh_b >= m_v_s)
{
BIGNUMBERBYLEO_ZERO
return;
}
//---
const int el_sh = int(b & 63); // numero de bits sobrandses en b
if(el_sh == 0)
{
//---
m_v_s -= el_sh_b;
//---
for(int i = 0; i < m_v_s; i++)
m_v[i] = m_v[i + el_sh_b];
//---
return;
}
//--- prev
const int slk = m_v_s; // locked size
const int shr = 64 - el_sh; // shr
m_v_s -= el_sh_b; // aqui lo reduicmos el tamaño V en numero de bloques
//--- iter
m_v[0] = (m_v[el_sh_b] >> el_sh); // primera escritura de bajos
int w = 0; // ahora empezamos apartir de aqui
for(int l = el_sh_b + 1; l < slk; l++)
{
const ulong y = m_v[l]; // curr temp
// previa rellenamos los altos (y se trunca a los bits que caben ahi)
// por eso ya no se requeriria mascara
m_v[w++] |= y << shr; // aqui ahora al (w) le aumentos los atlos
m_v[w] = (y >> el_sh); // nueva
}
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS(m_v, m_v_s)
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator>>(const ulong b) const
{
//--- neceistamos chekear dado que si size=1 pero "jalamos" 1 entonces queda en 0 (no peude ser 0 el size)
const int el_sh_b = int(b >> 6);
if(el_sh_b >= m_v_s)
return BigUInteger(0ULL, 1);
//---
const int el_sh = int(b & 63); // numero de bits sobrandses en b
if(el_sh == 0)
{
//---
const int vs = m_v_s - el_sh_b;
BIGINTEGERBYLEO_ALLOC_V
//---
for(int i = 0; i < m_v_s; i++)
v[i] = m_v[i + el_sh_b];
//---
return BigUInteger(v, vs);
}
//--- prev
const int shr = 64 - el_sh; // shr
int vs = m_v_s - el_sh_b; // aqui lo reduicmos el tamaño V en numero de bloques
BIGINTEGERBYLEO_ALLOC_V
//--- iter
m_v[0] = (m_v[el_sh_b] >> el_sh); // primera escritura de bajos
int w = 0; // ahora empezamos apartir de aqui
for(int l = el_sh_b + 1; l < m_v_s; l++)
{
const ulong y = m_v[l]; // curr temp
// previa rellenamos los altos (y se trunca a los bits que caben ahi)
// por eso ya no se requeriria mascara
m_v[w++] |= y << shr; // aqui ahora al (w) le aumentos los atlos
m_v[w] = (y >> el_sh); // nueva
}
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS(v, vs)
return BigUInteger(v, vs);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/*
//--- Suma en dos pasos
// La razon por la cual neceistmoas doble paso es el sigueinte
// Pongamos el siguiente ejemplo qeu tenemos base=10
// 99
// 91 caso en el que llevamos 1 y tenemos que usamr 9+9+1 si sumas todo tal cual tendiramso como reusto 9
// pero a y b son 9 ambos dfarian false.. asi que necesimoats hacelro en paso primero la suma tal cual
// pura 9+9 = 8 carray 1 luego 8+1 9 seria el reusto para ese digiti y ese seira el reustlado base
// esto pasa pro qeu si tenemos a+b el reusltaod sin carray prievio siemprte sera menor a aob
// pero con el carry esto peude cambiar y hacerlo igual por eso reueeirmos obtener el carry de ambas sumas
*/
//+------------------------------------------------------------------+
void BigUInteger::operator+=(const BigUInteger& b)
{
//--- Alg
const int lkc = m_v_s;
ulong carry = 0;
int i = 0;
//---
if(m_v_s > b.m_v_s) // this mayor
{
m_v_s++; // por si el carry
if(m_v_s > ArraySize(m_v))
ArrayResize(m_v, m_v_s, m_v_s);
//-- empezamos por b que es el menor
for(; i < b.m_v_s; i++)
{
const ulong s1 = (m_v[i] += b.m_v[i]); // suma 1
const ulong r = (m_v[i] += carry); // suma 2
carry = (s1 < b.m_v[i]) | (r < s1); // carry base, luego carray de al suma previa
}
// propagamos el carry
for(; i < lkc; i++)
{
const ulong r = (m_v[i] += carry);
carry = (r < carry);
}
}
else // el otro mayor
{
m_v_s = b.m_v_s + 1; // mayor
if(m_v_s > ArraySize(m_v))
ArrayResize(m_v, m_v_s, m_v_s);
//--- comun
for(; i < lkc; i++)
{
const ulong s1 = (m_v[i] += b.m_v[i]); // suma 1
const ulong r = (m_v[i] += carry); // suma 2
carry = (s1 < b.m_v[i]) | (r < s1); // carry base, luego carray de al suma previa
}
// carry
for(; i < b.m_v_s; i++)
{
const ulong r = b.m_v[i] + carry;
m_v[i] = r;
carry = (r < b.m_v[i]);
}
}
//---
if(carry)
m_v[i] = 1;
else
m_v_s--; // no hay carry exacto
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator+(const BigUInteger& b) const
{
BigUInteger v = this;
v += b;
return BigUInteger(v.m_v, v.m_v_s);
}
//+------------------------------------------------------------------+
void BigUInteger::operator+=(const ulong b)
{
//---
const ulong s1 = (m_v[0] += b);
//--- Hay carry
if(s1 < b)
{
//--- resize (por si acaso)
const int lkc = m_v_s;
if(++m_v_s > ArraySize(m_v))
ArrayResize(m_v, m_v_s, m_v_s);
//----
ulong carry = 1;
//--- iteracion
int i = 1;
for(; i < lkc; i++)
{
const ulong r = (m_v[i] += carry); // resultado
carry = (r < carry); // carry check
}
//--- carry final
if(carry) // si hay carry
{
m_v[i] = 1;
}
else // no hay
{
m_v_s--;
}
}
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator+(const ulong b) const
{
BigUInteger v = this;
v += b;
return BigUInteger(v.m_v, v.m_v_s);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BigUInteger::operator-=(const BigUInteger& b)
{
//----
ulong borrow = 0;
int i = 0;
//---
// Chekea ambos daod qeu b en caso pueda tener mas bytes esos ya no se procesan
for(; i < b.m_v_s && i < m_v_s; i++)
{
const ulong res_bor = m_v[i] - borrow; // paso 0 (a-resto)
const ulong res_f = res_bor - b.m_v[i]; // paso 1 (r-b)
borrow = (m_v[i] < borrow) | // en caso sea menor (tipo m_v es 0 y borro viene cno 1
// en ese caso tendremismo qeu prestarmos 1..
// Igual aqui si el left menor al right tendra uqe prestartse
(res_bor < b.m_v[i]);
//Print(res_f);
m_v[i] = res_f;
}
// sobra
for(; i < m_v_s; i++)
{
const ulong r = m_v[i] - borrow;
borrow = (m_v[i] < borrow); // si es menor enonces hubo uover
m_v[i] = r;
}
// Print(borrow);
// check
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS(m_v, m_v_s)
// maneo de underflow
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator-(const BigUInteger& b) const
{
BigUInteger v = this;
v -= b;
return BigUInteger(v.m_v, v.m_v_s);
}
//+------------------------------------------------------------------+
// si es 0 da underflow.
void BigUInteger::operator-=(const ulong b)
{
//---
// Chekea ambos daod qeu b en caso pueda tener mas bytes esos ya no se procesan
const ulong res_f = m_v[0] - b; // paso 1 (a-b)
if(m_v[0] < b) // si es menor hay borrow
{
ulong borrow = 1;
m_v[0] = res_f;
// sobra
for(int i = 1; i < m_v_s; i++)
{
const ulong r = m_v[i] - borrow;
borrow = (m_v[i] < borrow); // si es menor enonces hubo uover
m_v[i] = r;
}
// check
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS(m_v, m_v_s)
}
else
{
// No hay borrow
m_v[0] = res_f; // tal cual
}
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator-(const ulong b) const
{
BigUInteger v = this;
v -= b;
return BigUInteger(v.m_v, v.m_v_s);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BigUInteger::operator*=(const BigUInteger& b)
{
//--- min y max
int min, max;
if(m_v_s > b.m_v_s)
{
min = b.m_v_s;
max = m_v_s;
}
else
{
min = m_v_s;
max = b.m_v_s;
}
//--- resize
const int lks = m_v_s;
m_v_s += b.m_v_s;
//--- temp
ulong v[];
ArrayResize(v, m_v_s, m_v_s);
ArrayInitialize(v, 0ULL);
//--- Algoritmo de escuela simple
if(min < BIGNUMBERBYLEO_MUL_SCHOL_TO_KARATSUBA)
{
for(int i = 0; i < lks; i++)
{
// por cada digiito de b le multiples el digit curr a
ulong carry = 0;
//--- oeprando a
const ulong a = m_v[i];
const ulong a_lo = (uint)a; // parte baja
const ulong a_hi = a >> 32; // alta
//---
// iteraicon de digitos
for(int j = 0; j < b.m_v_s; j++)
{
ulong hi, lo;
BIGNUMBERSBYLEO_MUL64(b.m_v[j], hi, lo)
//--
// la suma en si es tipo (lo+hi+previo+carry)
// devido al carry y para evitar bugs
// lo haremos en pasos
// de dicha suma peude salir carry asi que eso lo vemos luegoi
// en esots 2 pasos no sumasmo hi dado que es el alto y ahi esta como el carry
// que luego pasaremos..
//--- lo+carry
const ulong sum1 = lo + carry; // suma1
//--- (prev) + curr
const ulong sum2 = sum1 + v[i + j];
//---
v[i + j] = sum2; // tal cual
//--- ahora armamos el carry
// hi (lo qeu se nos sale) +
// carray de la sum1
// carry de la suma2
carry = hi + (sum1 < lo) + (sum2 < lo);
}
//---- carry a la posicion final
if(carry)
v[i + b.m_v_s] = carry;
}
//---
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS(v, m_v_s)
}
else
{
// en caso este balanceado ratio ~2 no mucho
// max>min siempre y para uqe que cumpla esto:
// max<=min*2 osea que como minimo min = max/2
// no puede ser mayot ni menor tampoco 0 eso ya lo grantizamos por los ifs..
if(max <= (min << 1))
{
// metodo 2 Karatsuba
//--- ahora si codigo
// const int base_mitad = max >> 1; // mitad
//int o_a1 = base_mitad;
// int o
//--- ahora partimos: a
// this [][][][]
// BigUInteger()
// ArraySwap()
}
}
//--- Intercambiamos arrays
ArraySwap(m_v, v); // m_v=v y v=m_v
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator*(const BigUInteger& b) const
{
BigUInteger v = this;
v *= b;
return BigUInteger(v.m_v, v.m_v_s);
}
//+------------------------------------------------------------------+
void BigUInteger::operator*=(const ulong b)
{
//---
const int lkc = m_v_s;
if(++m_v_s > ArraySize(m_v))
ArrayResize(m_v, m_v_s, m_v_s);
//---
ulong carry = 0;
int i = 0;
for(; i < lkc; i++)
{
//--- mul (b * a) = hi\lo
const ulong a = m_v[i];
const ulong a_lo = (uint)a; // parte baja
const ulong a_hi = a >> 32; // alta
//- paso
ulong hi, lo;
BIGNUMBERSBYLEO_MUL64(b, hi, lo)
//--- parte baja
const ulong sum = carry + lo; // previo + 1
m_v[i] = sum;
//---
carry = hi + (sum < lo);
}
//---
if(carry)
m_v[i] = carry;
else
m_v_s--;
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator*(const ulong b) const
{
BigUInteger v = this;
v *= b;
return BigUInteger(v.m_v, v.m_v_s);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/*
// caso simple
// resto = divisor*cociente - diviendoo
// lo = dividendo
// b = divisor
// m_v[i] = cociente | q = cociente
*/
//---
#define BIG_UINTEGER_FULL_DIV_ALG(q) \
ulong resto = 0; \
for(int i = m_v_s - 1; i >= 0; i--) \
{ \
if(resto) \
{ \
q=CNumberUtils::Div128to64(resto, m_v[i], b, resto); \
} \
else \
{ \
const ulong lo = m_v[i]; \
q = lo / b; \
resto = lo - b * q; \
} \
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#define BIGINTGERBYLEO_DIVMOD_V_MOD (1)
#define BIGINTGERBYLEO_DIVMOD_V_DIV (2)
//---
struct BigUintegerMod
{
const uchar bytes[BIGINTGERBYLEO_DIVMOD_V_MOD];
};
struct BigUintegerDiv
{
const uchar bytes[BIGINTGERBYLEO_DIVMOD_V_DIV];
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template <typename TOp>
void BigUInteger::DivModInPlace(BigUInteger& b)
{
//--- Chekeos rapidos antes de ir a por el algoritmo com tal
const int divisor_len = b.m_v_s;
if(divisor_len == 1)
{
// Aplicamos para 1 limb
if(sizeof(TOp) == BIGINTGERBYLEO_DIVMOD_V_MOD)
{
this %= b.m_v[0];
}
else
{
this /= b.m_v[0];
}
return;
}
// el dividendo this es menor que el divisor?¿ en len
if(m_v_s < divisor_len)
{
if(sizeof(TOp) == BIGINTGERBYLEO_DIVMOD_V_DIV)
{
// cociente=0
BIGNUMBERBYLEO_ZERO
}
// Ahora si es mod como x/y donde x es menor a 0 el resto es x= (this) asi que no hace falta hacer
// nada ni cambiar tamaños.
return;
}
// Usaremos el mismo algoritmo qeu usamos en la division base
//---- Normalizamos
const int shift = CBitTricks::CLZ(b[divisor_len - 1]);
const int lkc = m_v_s;
//--- temporal b..
// Por un momenot le robamos los daots a b
// (luego le devolemos daod qeu bn es de solo lecutra no lo modifciaresmo)
// Entonces debido a eso no tiene sentido estar crenado copias si no las necesitamos
ulong bn[];
ArraySwap(bn, b.m_v);
// BigUInteger bn(b.m_v, divisor_len);
ulong div[];
//---
const int shr = 64 - shift;
if(shift > 0)
{
// Nada, entonces tenemos que modificar bn le devolvemos
ArraySwap(b.m_v, bn);
// Ahora dezplazamos y escalamos
//--- Normalizamos B
// Aplicamos .. para empzar a bn
ArrayResize(bn, divisor_len);
for(int i = divisor_len - 1; i > 0; i--)
bn[i] = (b[i] << shift) | (b[i - 1] >> shr);
bn[0] = b[0] << shift;
//---- Normalizamos el dividendo
const int ns = m_v_s + 1;
ArrayResize(div, ns);
// sig
// overflow aqui
div[lkc] = m_v[lkc - 1] >> shr;
for(int i = lkc - 1; i > 0; i--)
div[i] = (m_v[i] << shift) | (m_v[i - 1] >> shr);
div[0] = m_v[0] << shift; // ultimo
}
else
{
//--- Copiamos tal cual el dividendo
const int ns = m_v_s + 1;
// Si es div necesitamos un intermdio para el resto
// asi que no podemos eleigr m_v por que ya esta ocupado solo copiamos
if(sizeof(TOp) == BIGINTGERBYLEO_DIVMOD_V_DIV)
{
ArrayResize(div, ns);
ArrayCopy(div, m_v, 0, 0, m_v_s);
}
else
{
if(ns > ArraySize(m_v))
ArrayResize(m_v, ns); // lo agrandamos si hace falta
// ahora mismo div sera=m_v
ArraySwap(div, m_v);
}
//---
div[divisor_len] = 0;
}
//---
// Ahora reducimos el tamaño real..
// (dividendo len) - (divisor len)
m_v_s = lkc - divisor_len + 1;
//---- iteracion por cada digito del cociente
const ulong divisor_hi = bn[divisor_len - 1];
const ulong divisor_hi2 = bn[divisor_len - 2];
//---
for(int j = (lkc - divisor_len); j >= 0; j--)
{
//---
const int dividendo_pos = j + divisor_len;
//--- Estimacion inicial
// Dividos lso altos de div[] por el max alto de bn
ulong qhat, rhat;
if(div[dividendo_pos]) // mayor a 1 hay hi part
{
qhat = CNumberUtils::Div128to64(
div[dividendo_pos],
div[dividendo_pos - 1], divisor_hi, rhat);
}
else // 0 entonces division de toda la vida
{
qhat = div[dividendo_pos - 1] / divisor_hi;
rhat = (div[dividendo_pos - 1] - (divisor_hi * qhat));
}
//--- Correcion
while(true) // dado que n>1 siempre
{
ulong p_hi, p_lo;
// Multiplicamos
// qhat (cociente) * n-2 digito... la ide es ver si se pasa
CNumberUtils::Mul64to128(qhat, divisor_hi2, p_hi, p_lo);
//--- En caso sea mayot o en todo caso igual pero si el bajo mayor al digiot -2 del dividendo
const bool mayor = (p_hi > rhat) || (p_hi == rhat && p_lo > div[dividendo_pos - 2]);
if(!mayor)
break;
//--
qhat--;
const ulong lrhat = rhat;
rhat += divisor_hi;
//---
if(rhat < lrhat)
break;
}
//--- Ahora una vez correigdo multiplicamos y restamos
ulong borrow = 0;
// por cada digito del divisor lo multiplicmos por el qhat y restamos al this
// La idea aqui al igual qeu el algoritmo base
// es una vez que tenmas ese cocicnete lo multples con el divisor
// y luego le resmtoa al dividendno
for(int i = 0; i < divisor_len; i++)
{
//---
ulong p_hi, p_lo;
CNumberUtils::Mul64to128(qhat, bn[i], p_hi, p_lo);
//---
// sumar el borrow anterior al producto (p_hi:p_lo) + borrow
const ulong sum_lo = p_lo + borrow;
const ulong sum_hi = p_hi + (sum_lo < p_lo);
// restamos
const ulong old = div[i + j];
div[i + j] = old - sum_lo;
//--- lo que prestamos
borrow = sum_hi + (old < sum_lo);
}
//---
const ulong old_top = div[dividendo_pos];
div[dividendo_pos] = old_top - borrow;
//--- en caso haya underflow debemso de corregir esa estimacion en -1
// por lo tanatmos debemos de sumar 1 veces el divisor al diviendo
if(old_top < borrow)
{
//---
qhat--;
//---
ulong carry = 0;
for(int i = 0; i < divisor_len; i++)
{
// le sumasmo a cada digito +1 veces el diivsor real
ulong s2 = div[i + j] + bn[i];
// overflow al sumar
ulong c_out = (s2 < div[i + j]);
// lo añadimos al carry
s2 += carry;
// puede haber overflow al sumar el carray a s2 asiq eu tambien lo agregmoa a cout
c_out += (s2 < carry); // overflow al sumar el carry
// escribismo devuelta
div[i + j] = s2;
// assing
carry = c_out;
}
// añadimos carry
div[dividendo_pos] += carry;
}
//--- Escribimos en this el resultado tal cual
if(sizeof(TOp) == BIGINTGERBYLEO_DIVMOD_V_DIV) // solo si es div modificamos m_v
{
if(qhat == 0)
{
m_v_s--; // Reducimos tamaño
//Print("redux");
continue;
}
//---
//PrintFormat("qhat[%d] = %I64u", j , qhat);
m_v[j] = qhat;
}
}
//---
if(sizeof(TOp) == BIGINTGERBYLEO_DIVMOD_V_DIV) // en caso sea div
{
// no nos interesa el rest solo deovlelr a b lo qeu le tomamos prestado
if(shift == 0)
ArraySwap(b.m_v, bn); // le devolvemos el valor..
}
else
{
//---
// AQUI NO hace falta resize pro qeu m_v_s>divisor_len anteriormente ya se chekeo
//---
m_v_s = divisor_len; // tiene el valor de divisor len inicalemtne
if(shift > 0)
{
//---
const int last = divisor_len - 1;
m_v[last] = div[last] >> shift;
if(!m_v[last])
m_v_s--;
//---
for(int i = last - 1; i >= 0; i--)
{
m_v[i] = (div[i] >> shift) | (div[i + 1] << shr);
if(!m_v[i])
m_v_s--; // restmoas es 0
}
}
else
{
//---
//Print("hola");
// intercambiamos ahora m_v le quita lo quie le dio a div
ArraySwap(m_v, div);
//---
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS(m_v, m_v_s)
//---
// Le devolvemos lo qeu tomamos prestado a b
ArraySwap(b.m_v, bn); // le devolvemos el valor..
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
__forceinline void BigUInteger::operator/=(BigUInteger& b)
{
DivModInPlace<BigUintegerDiv>(b);
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator/(BigUInteger& b) const
{
BigUInteger v = this;
v /= b;
return BigUInteger(v.m_v, v.m_v_s);
}
//+------------------------------------------------------------------+
void BigUInteger::operator/=(const ulong b)
{
//---
BIG_UINTEGER_FULL_DIV_ALG(m_v[i])
//---
// peude dehjar 0
// 256 | 3 -- aqui pro jeemplo 2/3=0
// 0
// 256 | 3
// 24 08 ---
// -16 | 3
// 085
// 15
// -1
// quedo 085
// entonces eso lo tenemos que limpiar 85 resto 1
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS(m_v, m_v_s)
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator/(const ulong b) const
{
BigUInteger v = this;
v /= b;
return BigUInteger(v.m_v, v.m_v_s);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
__forceinline void BigUInteger::operator%=(BigUInteger& b)
{
DivModInPlace<BigUintegerMod>(b);
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator%(BigUInteger& b) const
{
BigUInteger v = this;
v %= b;
return BigUInteger(v.m_v, v.m_v_s);
}
//+------------------------------------------------------------------+
void BigUInteger::operator%=(const ulong b)
{
//--- algorimo en comun
BIG_UINTEGER_FULL_DIV_ALG(m_v[i])
//--- el resto siempre queda en un rango menor a ULONG_MAX o igual asi que truncamos el tamaño
m_v_s = 1; // truncamos el size
m_v[0] = resto; // asiganamos
}
//+------------------------------------------------------------------+
ulong BigUInteger::operator%(const ulong b) const
{
ulong q;
BIG_UINTEGER_FULL_DIV_ALG(q)
return resto;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ulong BigUInteger::Gdc(ulong r) const
{
//---
// a = this
// b = r (prev_r)
ulong prev_r = r;
//--
// Primera division (Big / nuimber)
r = this % r; // div / r
// Luego de aqui un gdc normal dado que r<r (osea cabe en ulong)
// luego
// a = prev_r
// b = r
//--- apartir de ahora gcd entre prev_r y r
if(r == 0ULL)
return prev_r;
// usaremos algortimo binario para esto (stein)
// Lo primro que haremos sera calclar el ctz (baiinamte el min 2s uq ehay en amboss)
// osea si tenemos a y b entonces ambos numeros se peuden escribri tal que
// a = 2x+r
// b = 2y+r
// la idea es encontrar el minimo en ambos.. y normalzialo a esa escala
ulong full = r | prev_r; // Or para combinar
full = TSNTABLES_BIT_DEJAR_SOLO_MINUS_SIG_BYTE(full);
// la idea es ver cuantos "2" comunes tenemos
const int shift = TSNTABLES_CTZ_64_GET_BIT(full); // ya tenemos el bit exacto (cuantos 2s..)
//--- ahora pelamos a (u (r))
// gcd(u, 2v) = gcd(u, v), solo si u es impar esto dado qeu 2 no es un divisor comun entre dos
// reduimos su valor
full = TSNTABLES_BIT_DEJAR_SOLO_MINUS_SIG_BYTE(r);
r >>= TSNTABLES_CTZ_64_GET_BIT(full);
//---
while(r)
{
// prev_r posiblemte viene de ser par o impar neismo shjacelro impar.
//-- quyitamos los 2s (la idea tambien es hacer a prevr = v impar)
full = TSNTABLES_BIT_DEJAR_SOLO_MINUS_SIG_BYTE(prev_r);
prev_r >>= TSNTABLES_CTZ_64_GET_BIT(full);
//--- ahora si restamos
// la idea con restar es que "esa division" normal la podemos hacer resntado x veces > 0, entonces aqui lo mismo
// pero tenemos que tener cuidado con los negativos en ese caso "swap" de resta
//---
// la idea es que el mod clasifiaco para obtener el resto
// lo podemos sacar restamos sucesivamnte (claramente en mas pasos pero se logra)
// aqui tamiben se usa: gdc(u,v)=gdc(u,v-u) (como ambos son impares (por disñeo el 1 siempre activo))
if(prev_r < r)
{
// punto de cambio... (igual que el temp previo. en la versino cno %)
// aqui es menor .. resta al revez y temporal para volver a asingar
const ulong t = prev_r;
prev_r = r - prev_r;
r = t;
}
else
prev_r -= r;
}
//---
return prev_r << shift;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template <typename TRandom>
bool BigUInteger::IsProbablePrime(int rounds) const
{
// 1 es primo
if(this < 2)
return false;
// 2 es primo
// 3 para evitar que (n-2 = 1 y generar un numero [0,0] aletaorio
// co sa que no tiene sntido asi que lo descartamos aqui)
if(this == 2 || this == 3)
return true;
// todo par no es primro (>2)
if(BIGNUMERBYLEO_UINTEGER_IZ_PAR)
return false;
// Ahora si empezemos primero lo descomponemos
// copia #1
const BigUInteger n_menos1 = this - 1;
// copia #2
const BigUInteger n_menos2 = n_menos1 - 1;
// copia #3
// CTZ seguro dado qeu mnoes como minimo sera 4 (5-1)
const ulong s = n_menos1.Ctz();
// ahora aplicamos dicho s a d (d>>s)
const BigUInteger d = n_menos1 >> s; // assing
//----
// copia #4
BigUInteger a(EMPTY_INITIAL_RESERVE, n_menos2.m_v_s); // reservamos exacta para a
for(int i = 0; i < rounds; i++)
{
// [0, n-2] excl, (a = res)
// intemante no modifca tamaño solo llena (nada de resize)
//TRandom::RandomBigRange(n_menos2, a);
a.<TRandom>FillRandomRange(n_menos2);
// ajustamos 2>
a += 2;
// a=base
// d=Exp
// this=n
a.PowMod(d, this); // inplace
if(a == 1 || a == n_menos1)
continue;
bool compuesto = true;
for(ulong r = 1; r < s; r++)
{
a.PowMod(2, this); // a = a^2 mod n , inplace
if(a == n_menos1)
{
compuesto = false;
break;
}
}
//---
if(compuesto)
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// pow mod inplace
void BigUInteger::PowMod(const ulong e, const BigUInteger &n)
{
}
//+------------------------------------------------------------------+
void BigUInteger::PowMod(const BigUInteger& e, const BigUInteger &n)
{
}
//--- end namespace
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/*
a b = A *
c d = B
- -
(Carry) (a*d+Carry)(b*d)
(c*a) (c*b)
--------------------------
*/
//+------------------------------------------------------------------+
//
#endif // BIGNUMBERSBYLEO_SRC_BASE_UINT_MQH
// a += b