BigNumberByLeo/Src/Base/Main.mqh

2120 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_MAIN_MQH
#define BIGNUMBERSBYLEO_SRC_BASE_MAIN_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "..\\Utils\\Main.mqh"
#include "Def.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//#define BIGINTGERBYLEO_MACRO_AS_FUNCION
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/* 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
*/
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// 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
#define BIGNUMERBYLEO_UINTEGER_IZ_ZERO (m_v_s == 1 && m_v[0] == 0ULL)
#define BIGNUMERBYLEO_BITS_TO_LIMBS(v) (v>>6)
#define BIGNUMERBYLEO_LIMBS_TO_BITS(v) (v<<6)
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
struct BigUInteger
{
public:
//---
ulong m_v[];
int m_v_s;
//--- Constructores
// raw se transfiere (swaping)
BigUInteger(ulong& v[], const int vs_8);
//-- high
BigUInteger(const string& str, int base); // desde string (Base 10)
BigUInteger(const long number); // si se quiere iniciar desde un numero
BigUInteger(const int& e[], int initial_reserve);
BigUInteger(const double& e[], const long number);
BigUInteger();
//-- Vacio inica desde bytes
BigUInteger(const uchar& bytes[], int byteorder);
//--- unitarios
//-- Negacion
BigUInteger operator~() const;
//--- bit simples
//-- and
void operator&=(const BigUInteger& b);
BigUInteger operator&(const BigUInteger& b) const;
__forceinline ulong operator&(const long _b) const;
//-- or
void operator|=(const BigUInteger& b);
BigUInteger operator|(const BigUInteger& b) const;
BigUInteger operator|(const long _b) const;
//-- xor
void operator^=(const BigUInteger& b);
BigUInteger operator^(const BigUInteger& b) const;
BigUInteger operator^(const long _b) const;
//-- dezplazamientos
// left
void operator<<=(const long _b);
BigUInteger operator<<(const long _b) const;
// right
void operator>>=(const long _b);
BigUInteger operator>>(const long _b) const;
//---- aritmeticos
//- suma
void operator+=(const BigUInteger& b);
BigUInteger operator+(const BigUInteger& b) const;
void operator+=(const long _b);
BigUInteger operator+(const long _b) const;
//- resta
void operator-=(const BigUInteger& b);
BigUInteger operator-(const BigUInteger& b) const;
void operator-=(const long _b);
BigUInteger operator-(const long _b) const;
//- mul
void operator*=(const BigUInteger& b);
BigUInteger operator*(const BigUInteger& b) const;
void operator*=(const long _b);
BigUInteger operator*(const long _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 long _b);
BigUInteger operator/(const long _b) const;
//- mod
__forceinline void operator%=(BigUInteger& b);
BigUInteger operator%(BigUInteger& b) const;
void operator%=(const long _b);
ulong operator%(const long _b) const;
//--- compracion
// basicas
bool operator>(const BigUInteger& b) const;
bool operator>=(const BigUInteger& b) const;
bool operator==(const BigUInteger& b) const;
// derivadas
__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); }
// zero
__forceinline bool IsZero() const { return BIGNUMERBYLEO_UINTEGER_IZ_ZERO; }
__forceinline bool IsNotZero() const { return !BIGNUMERBYLEO_UINTEGER_IZ_ZERO; }
//--- acceso a limbs (sin chekeo raw maxima velociad)
__forceinline ulong operator[](const int limb_idx) const { return m_v[limb_idx]; }
//--- complejos
// this = base
// e = exp (long)
// n = (mod n)
BigUInteger PowMod(const long e, const BigUInteger& n);
// Es probasblemnete un primo?¿
bool IsProbablePrime(int rounds);
// GCD Maximo comun divisor normal
// = gdc(this, v) (retrona ulong)
ulong Gdc(const ulong v) const;
//---
// GDC extenndio para retonar x:
// si tenemos:
// ax+by=gdc(a,b)
// osea:
// this*x+b*y=gdc(this,b)
// Esta funcion retorna el (x)
// Tambien se peude ver como si se tratase de obtener el inveosr modular de this, donde b es el mod
// this * x = 1 (mod b)
BigUInteger GdcExtendedRetX(const BigUInteger& b);
//--- From
void FromBytesLE(const uchar& buf[]);
void FromBytesBE(const uchar& buf[]);
//--- Utilidades
// TRandom debe generar n limbs
template <typename TRandom>
__forceinline void FillRandom();
//--- To
//- 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;
//- string
int ToString(uchar& buf[]) const;
//---
static const int EMPTY_INITIAL_RESERVE[1];
static const double EMPTY_NUMBER_EXACT[1];
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
const int BigUInteger::EMPTY_INITIAL_RESERVE[1] = {0};
const double BigUInteger::EMPTY_NUMBER_EXACT[1] = {0.0};
//+------------------------------------------------------------------+
//| Constructores |
//+------------------------------------------------------------------+
// Nota v ya muere ahi noramlte esto lo usarimos en operator
// pro que ahora v tiene size=0 nada
BigUInteger::BigUInteger(ulong &v[], const int vs_8)
: m_v_s(vs_8)
{
// ahora m_v tiene el desipcrity de v y asi rotan
ArraySwap(m_v, v);
}
//+------------------------------------------------------------------+
// exacto
// casos de uso (pro ejemplo get extendner retx con un numero normal
// perimo hay qeu converit a big integer si usas el contrucot normal te reserva mucho espcio
// asi que usamos lo nceisa solo 1 dado qeu no lo usaremos mas.. este es ele caso de uso)
BigUInteger::BigUInteger(const double &e[], const long number)
: m_v_s(1)
{
ArrayResize(m_v, 1);
m_v[0] = ulong(number);
}
//+------------------------------------------------------------------+
BigUInteger::BigUInteger(const long number)
: m_v_s(1)
{
ArrayResize(m_v, 32, 32); // tamaño inicial de reserva
m_v[0] = ulong(number);
}
//+------------------------------------------------------------------+
BigUInteger::BigUInteger()
: m_v_s(1)
{
ArrayResize(m_v, 32, 32); // tamaño inicial de reserva
m_v[0] = 0ULL;
}
//+------------------------------------------------------------------+
BigUInteger::BigUInteger(const int &e[], int initial_reserve)
: m_v_s(1)
{
ArrayResize(m_v, initial_reserve, initial_reserve);
m_v[0] = 0ULL;
}
//+------------------------------------------------------------------+
BigUInteger::BigUInteger(const string& str, int base)
: m_v_s(1)
{
//---
const int digtis = g_tsn_biguinteger_base_max[base];
if(digtis < 0)
{
// En caso de error lo inciamos como 0
ArrayResize(m_v, 32, 32);
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)
{
if(byteorder == BIGUINTEGER_LOADBYTES_BE)
FromBytesBE(bytes);
else
FromBytesLE(bytes);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#define BIGUINTGER_LOADFROMBYTES_CHECK \
if(k < 1) \
{\
if(ArraySize(m_v) < 1)\
ArrayResize(m_v, 32, 32);\
m_v_s = 1;\
m_v[0] = 0ULL;\
return; \
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template <typename TRandom>
// firma esperada (const ulong& in, const int ins)
__forceinline void BigUInteger::FillRandom()
{
TRandom::Random(m_v, m_v_s);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BigUInteger::FromBytesLE(const uchar& buf[])
{
//---
const int k = ArraySize(buf);
BIGUINTGER_LOADFROMBYTES_CHECK
//---
if(k > ArraySize(m_v))
ArrayResize(m_v, k, k);
//---
const int sob = k & 7; // % 8 cuantos sobraan
const int blocks = k - sob; // Cuantos bloques enteros procesaremos
//--- Ahora si
m_v_s = 0;
int r = 0;
// bloques completos
for(; r < blocks;)
{
//--- 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)
{
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++;
}
//--- Limpiamos zeros altos..
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS
}
//+------------------------------------------------------------------+
// 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);
BIGUINTGER_LOADFROMBYTES_CHECK
//---
if(k > ArraySize(m_v))
ArrayResize(m_v, k, k);
//---
const int sob = k & 7; // % 8 cuantos sobraan
const int blocks = k - sob; // Cuantos bloques enteros procesaremos
//--- Ahora si
int r = blocks - 1;
// bloques completos
for(; r >= 0;)
{
//--- 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 = sob - 1; // reinicamos dado qeu peude ser (-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++;
}
//--- Limpiamos zeros altos..
BIGNUMBERSBYLEO_CLEAN_HIGH_ZEROS
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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;
//---
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;
//---
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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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 BigUInteger(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[];
int vs = m_v_s;
//---
if(b.m_v_s < vs)
{
// b es menor lo qeu se nos aplica es menor [1][0] &= [2]
vs = b.m_v_s; // lo bajamos
}
//---
ArrayResize(v, vs);
//---
for(int i = 0; i < vs; i++)
v[i] = m_v[i] & b.m_v[i];
//---
return BigUInteger(v, vs);
}
//+------------------------------------------------------------------+
__forceinline ulong BigUInteger::operator&(const long _b) const
{
return m_v[0] & ulong(_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)
for(; i < m_v_s; i++)
m_v[i] = b.m_v[i];
}
}
//+------------------------------------------------------------------+
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
for(; i < vs; i++)
v[i] = b.m_v[i];
}
//---
return BigUInteger(v, vs);
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator|(const long _b) const
{
//---
ulong v[];
ArrayResize(v, m_v_s);
v[0] = m_v[0] | ulong(_b);
// copia
for(int i = 1; i < m_v_s; i++)
v[i] = m_v[i];
//---
return BigUInteger(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)
for(; i < m_v_s; i++)
m_v[i] = b.m_v[i];
}
}
//+------------------------------------------------------------------+
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
for(; i < vs; i++)
v[i] = b.m_v[i];
}
//---
return BigUInteger(v, vs);
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator^(const long _b) const
{
//--- hay data alemnos 1
ulong v[];
ArrayResize(v, m_v_s);
v[0] = m_v[0] ^ ulong(_b);
// copia
for(int i = 1; i < m_v_s; i++)
v[i] = m_v[i];
//---
return BigUInteger(v, m_v_s);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BigUInteger::operator<<=(const long _b)
{
//---
const ulong b = ulong(_b);
const int els = int(b >> 6); // b / 64
const int els_sob = int(b & 63); // % 64
//---
if(els_sob == 0) // exacto
{
//---
m_v_s += els;
if(m_v_s < ArraySize(m_v))
ArrayResize(m_v, m_v_s);
//---
int i = m_v_s - 1;
for(; i >= els; i--)
m_v[i] = m_v[i - els];
//---
for(; i >= 0; i--)
m_v[i] = 0ULL;
//---
return;
}
//---
int r = m_v_s - 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
//---
m_v_s += els;
int w = m_v_s - 1; // escritura en els-1 (depende de que tantos salots elsb haya)
if(overflow)
{
if(++m_v_s > ArraySize(m_v)) // si la reserva actual es menor al vactual
ArrayResize(m_v, m_v_s);
m_v[m_v_s - 1] = overflow;
}
else
{
// no hay ovw enotnces nada
if(m_v_s > ArraySize(m_v)) // si la reserva actual es menor al vactual
ArrayResize(m_v, m_v_s);
}
//--- iter
while(r > 0)
{
const ulong prev = m_v[--r]; // valor previo
m_v[w--] = (hi << els_sob) | (prev >> srh); // (valor alto dezplaado) | (valor bajo overflow siguiente)
hi = prev; // ahora el alto es nuestro prev (Curr)
}
m_v[w] = hi << els_sob; // terminos con el valor 0 o ultimo
}
//+------------------------------------------------------------------+
// crea uno nuevo
BigUInteger BigUInteger::operator<<(const long _b) const
{
//---
const ulong b = ulong(_b);
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 long _b)
{
//---
const ulong b = ulong(_b);
const int el_sh_b = int(b >> 6);
const int el_sh = int(b & 63); // numero de bits sobrandses en b
if(el_sh == 0)
{
// si es 0
if(el_sh_b == 0)
{
m_v_s = 1;
m_v[0] = 0ULL;
return;
}
//---
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; 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
}
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator>>(const long _b) const
{
//---
const ulong b = ulong(_b);
const int el_sh_b = int(b >> 6);
const int el_sh = int(b & 63); // numero de bits sobrandses en b
if(el_sh == 0)
{
// si es 0
if(el_sh_b == 0)
{
return BigUInteger();
}
//---
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
const 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; 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
}
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 long _b)
{
//---
const ulong b = 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 long 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
// maneo de underflow
}
//+------------------------------------------------------------------+
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 long _b)
{
//---
// Chekea ambos daod qeu b en caso pueda tener mas bytes esos ya no se procesan
const ulong b = ulong(_b);
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
}
else
{
// No hay borrow
m_v[0] = res_f; // tal cual
}
// maneo de underflow
// nota que aqui el underflow tipo 5 - 10
// oasaria qeu aqui si se manjea el compilador ya lo hace auto
// dado qeu el unico caso para que peuda usceder es que m_v[0] sea menor a b
// no hay otro
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator-(const long _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;
}
//--- sumamos el carry al final
//--- Añadimos (posicion final)
/* int pos = ;
while(carry != 0)
{
const uint64_t sum = v[pos] + carry;
v[pos] = sum;
carry = sum < v[pos]; // sale entonces reuqier + 1
pos++; // siguiente posicion
}*/
}
//---
while(m_v_s > 0 && v[m_v_s - 1] == 0)
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
/*
El metodo dos parte de interpeteat a:
a*b
como dos polinomios
a=a1*x^m+a0
b=b1*x^m+b0
donde:
a1=parte alta
a0=parte baja
x=base
m=(numero de digitos del numero en si entre 2)
Esto es posible dado que expresamos el numero como dos partes (tipo) notacion
cientiica una base elevado a la mitad de digitiso*valorbajo + valor ato ejemplo
120000 ()
x=10
m=3 (6/2)
a=120*10^3+0=120000
Ahora si mulltiplacas estos dos polinomios tal que:
a*b= (a1*x^m+a0) * (b1*x^m+b0)
=
(a1*x^m+a0) *
(b1*x^m+b0)
--------------------
= (a1*x^m)(b1*x^m)+a0(b1*x^m)+b0(a1x^m)+(a0b0)
Ahora reordenamos
a1b1x^m2+a0(b1*x^m)+b0(a1x^m)+(a0b0)
Podemos sacar a x^m como factor comun ahi
x^m(a0b1+b0a1)
Queda:
a1b1x^m2+x^m(a0b1+b0a1)+a0b0
Ahora la idea por lo qeu entendi es que ahora mismo estasmo ejecutnado una multiplacion de toda la vida
ahora la idea es simplificar
para eso (a0b1+b0a1) esto que podemos verlo como (ab+cd) tenemos aqui 4 terminos..
diferentes por lo qeu no podemos factoriuzalo lo qeu si es que podemos aprovechar
algo interesante:
(a+b)(c+d) = ac+ad+bc+bd
Esto es multiplacion de binomios..
la idea e sque si interpatmaos ese a0b1+b0a1 como eso nos da:
(a0+a1)(b0+b1) =
a0b0+a0b1+a1b0+a1b1
Nota que eligmos esa convinacion para poder aplicar el truco que usaremos ahora
Esto si te das cuenta ciertas partes ya las tenemos... a0b0 y b1a1 ya los tenemso calculados
entonces renombrando:
(a0+a1)(b0+b1) = z0 + a0b1+a1b0 + z2
donde:
z2 = b1a1
z0 = a0b0
reordenmoas la parte izq:
= (a0b1+a1b0) + z0 + z2 (no imprta el orden dado que es suma propiedad comutativa)
ahora pasamos al otro lado
z2 - z0 - (a0+a1)(b0+b1) = a0b1+a1b0
o tambien:
a0b1+a1b0 = (a0+a1)(b0+b1) - z0 - z2
bueno entonces con eso ya podemos calucalr lo que nos falta para tener z1 con 3 multiplaciones
(z0, z2 y la de ()()) en vez de 4...
entcones la funcion seira algo asi
primero calcullkos z0 y z2 primero eso y luego z1 (a0b1+a1b0)
sale claucalos = (a0+a1)(b0+b1) - z0 - z2
luego de eso aplicas el x^m
Ejemplo multipllacar
10
45
x=10
m=1
a = 1*10^1+0 , osea que a1=1, a0=0
b = 4*10^1+5 , osea que b1=4, b0=5
calculomoes z0 (b1a1 ) y z2 (a0b0)
z0=1*4=4
z2=0*5=0
ahora z1
z1=(a0+a1)(b0+b1) - z0 - z2
remplazando:
(0+1)(5+4) - 0 - 4
(1)(9) - 0 - 4
9 - 0 - 4
9 - 4
z1=5
final remplzamos en:
z0x^m2+x^mz1+z2 = 4*100+10*5+0= 400 + 50 + 0 = 450
*/
//--- 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 long _b)
{
//---
const ulong b = 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 long _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) \
const ulong b = ulong(_b); \
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
m_v_s = 1;
m_v[0] = 0ULL;
}
// 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 = 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
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.m_v);
// Ahora dezplazamos y escalamos
//--- Normalizamos B
// Aplicamos .. para empzar a bn
ArrayResize(bn.m_v, divisor_len);
for(int i = divisor_len - 1; i > 0; i--)
bn.m_v[i] = (b[i] << shift) | (b[i - 1] >> shr);
bn.m_v[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
{
//--- Ahora el diviosr (bn)
// Se presta tal cual no hace falta crear copias inncesarias
//--- Copiamos tal cual el dividendo
const int ns = m_v_s + 1;
ArrayResize(div, ns);
ArrayCopy(div, m_v, 0, m_v_s);
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.m_v); // 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");
int i = divisor_len - 1;
for(; i >= 0; i--)
{
if(div[i] == 0)
m_v_s--;
}
//--- ahora si copiamos
ArrayCopy(m_v, div, 0, 0, m_v_s); //
// Le devolvemos lo qeu tomamos prestado a b
ArraySwap(b.m_v, bn.m_v); // 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 long _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
}
//+------------------------------------------------------------------+
BigUInteger BigUInteger::operator/(const long _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 long _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 long _b) const
{
ulong q;
BIG_UINTEGER_FULL_DIV_ALG(q)
return resto;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ulong BigUInteger::Gdc(ulong r) const
{
//---
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)
//--- 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 ambos)
ulong full = r | prev_r;
full = TSNTABLES_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(full);
// la idea es ver cuantos "2" comunes tenemos
const int shift = TSNTABLES_SWAR_64_GET_BIT(full);
//--- 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_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(r);
r >>= TSNTABLES_SWAR_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_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(prev_r);
prev_r >>= TSNTABLES_SWAR_64_GET_BIT(full);
//--- ahora si restamos
// 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 = prev_r - r;
}
//---
return prev_r << shift;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BigUInteger::IsProbablePrime(int rounds)
{
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//a=this
//b=b
BigUInteger BigUInteger::GdcExtendedRetX(const BigUInteger& b)
{
//--
return this;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BigUInteger BigUInteger::PowMod(const long e, const BigUInteger &n)
{
BigUInteger resultado(1);
return BigUInteger();
}
//--- end namespace
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/*
a b = A *
c d = B
- -
(Carry) (a*d+Carry)(b*d)
(c*a) (c*b)
--------------------------
*/
//+------------------------------------------------------------------+
//
#endif // BIGNUMBERSBYLEO_SRC_BASE_MAIN_MQH
// a += b