Sono un chimico con l’hobby della matematica uso Mathematica del Wolfram e quindi non ho problemi per trovare Mod[a,b]. Anche per trovare l’approssimazione all’intero più vicino uso Floor[c]; usando linguaggi di programmazione tipo qbasic tbasic ecc.. le operazioni Mod e Int si possono fare tranquillamente ma quando il numero eccede un certo valore il programma va in overflow. Problema: esiste un algoritmo matematico che permetta di calcolare Mod o Int quando i numeri sono molto grandi (es 10^40) senza usare Mathematica?

Se Mathematica lo fa è
scontato che esista un algoritmo, ma a parte commenti di
basso livello come questo, il problema non è
particolarmente complicato, se si decide di usare tipi di
dati forniti dal linguaggio senza ricorrere ad una
codifica binaria particolare, su un numero variabile di
byte.

Per prima cosa dovresti
usare la variabile numerica più grande, che dipende dal
linguaggio. In C/C++ è il long double che arriva a
numeri dell’ordine di ± 1.2E ± 4932 (19 cifre
significative).

Una volta scelto il tipo
della variabile, il problema rimane “solo” il
calcolo delle funzioni che t’interessano.

Premetto che in C/C++
esistono delle versioni delle funzioni che cerchi per
variabili long double, ma se mi limitassi a dire questo
rimarresti deluso, quindi ti propongo alcune soluzioni,
magari non le migliori possibili, ma pur sempre
soluzioni.

Per il modulo esiste in
molti linguaggi il relativo operatore, ma se non sbaglio
è utilizzabile solo con numeri interi, per ragioni
legate all’efficienza del codice.

Questo esclude il suo
uso nel nostro caso, per cui lo calcoliamo in C/C++ nel
seguente modo:

long double mod(long double a, long double b)
{
  return a-(long int)(a/b)*b;	// (long int)x arrotonda per difetto il valore di x
} 

Questo potrebbe
funzionare a patto che la divisione a/b non superi i 2
miliardi, ma credo che nel tuo caso preferiresti qualcosa
di migliore, per cui si potrebbe usare il banale, lento,
ma corretto algoritmo delle sottrazioni, ossia si prende a
e si continua a sottrarre b, finché a è
maggiore di b.

long double mod(long double a, long double b)
{
  while(a>=b) a-=b;	// l’operatore -= equivale a scrivere a=a-b
  return a;
} 

Ti renderai conto che
questo tipo di approccio è improponibile nel caso a
sia molto più grande di b, per cui si potrebbe
tentare una strada che mette insieme i due metodi.

long double mod(long double a, long double b)
{
unsigned long n; // Numero dei volte che b sta in a
long double k; // Costante da sottrarre nel ciclo
n=1<<31; // Sposto il un bit nella 31a posizione che in binario significa 2^31=2147483648

while(n!=0) {
if(a>=n*b) { // Se a è maggiore di un blocco di b posso fare il ciclo di sottrazioni dei blocchi
k=b*n; // Calcolo la dimensione del blocco
while(a>=k) a-=k;
}
n>>=1; // Dimezzo la dimensione del blocco
}
   return a;
} 

In parole povere la
tecnica consiste nel togliere ad a dei blocchi di b,
in modo da accellerare la sottrazione. Per determinare la
dimensione dei blocchi uso un semplice intero lungo, in
cui metto un solo bit che poi “shifto” a destra
(divido per due, ma in tempi quasi nulli visto che
l’operazione di shift corrisponde ad una sola
istruzione in linguaggio macchina).

Per quanto riguarda la
funzione che trova il numero intero uguale
all’argomento senza cifre decimali, si potrebbe
risolvere semplicemente con un type-cast ad un tipo di
dato intero (i=(long int)x;), ma come prima non lo
possiamo fare visto che nessuna variabile intera può
contenere numeri tanto grandi quanto un long double, per
cui anche questa volta bisogna ricorrere a un algoritmo
che sia il più efficiente possibile.

La prima cosa che mi
viene in mente è manipolare la rappresentazione binaria
del numero, eliminando i decimali, ma questo non è
possibile in tutti i linguaggi. Questa volta ti risparmio
algoritmi banali e passo subito alla soluzione più
semplice grazie al lavoro precedente. Infatti la parte
intera di un numero si può ottenere semplicemente
togliendo i decimali, che si possono ricavare tramite la
funzione precedente cercando il resto della divisione per
1, e quindi:

long double Int(long double x)
{
    return x-mod(x,1);
}