Differenze tra le versioni di "Gestire numeri superiori al limite massimo supportato dal tipo Long"

Da Gambas-it.org - Wikipedia.
 
Riga 1: Riga 1:
Come è noto, in Gambas il tipo di variabile ''Long'' in Gambas è capace di contenere valori ''positivi'' non superiori al numero ''9.223.372.036.854.775.807''. <SUP>&#091;[[#Note|Nota 1]]&#093;</sup>
+
Come è noto, in Gambas il tipo di variabile ''Long'' in Gambas è capace di contenere valori ''positivi'' non superiori al numero ''9.223.372.036.854.775.807''. <SUP>&#091;[[#Note|nota 1]]&#093;</sup>
  
Per poter ottenere dalla somma (o dalla moltiplicazione) di due o più numeri un risultato superiore al limite massimo rappresentabile in Gambas dal valore ''Long'', si potranno adottare alcune modalità <SUP>&#091;[[#Note|Nota 2]]&#093;</sup><SUP>&#091;[[#Note|Nota 3]]&#093;</sup> che di seguito descriveremo.  
+
Per poter ottenere dalla somma (o dalla moltiplicazione) di due o più numeri un risultato superiore al limite massimo rappresentabile in Gambas dal valore ''Long'', si potranno adottare alcune modalità <SUP>&#091;[[#Note|nota 2]]&#093;</sup><SUP>&#091;[[#Note|nota 3]]&#093;</sup> che di seguito descriveremo.  
  
==Uso della Classe Classe "''BigInt''" del Componente ''gb.gmp''==
+
==Uso della Classe Classe ''BigInt'' del Componente ''gb.gmp''==
Per poter superare i limiti del suo nativo tipo ''Long'', Gambas fornisce un apposito Componente, denominato "''[http://gambaswiki.org/wiki/comp/gb.gmp?en gb.gmp]''". In particolare questo Componente è costituito da due Classi: "''BigInt''", che rappresenta un numero intero con numero potenziale illimitato di cifre, e "''Rational''", dedicato alla gestione dei numeri razionali.
+
Per poter superare i limiti del suo nativo tipo ''Long'', Gambas fornisce un apposito Componente, denominato "''[http://gambaswiki.org/wiki/comp/gb.gmp?en gb.gmp]''". In particolare questo Componente è costituito da due Classi: ''BigInt'', che rappresenta un numero intero con numero potenziale illimitato di cifre, e "''Rational'' ", dedicato alla gestione dei numeri razionali.
  
 
Mostriamo un semplice esempio pratico di utilizzo della Classe ''BigInt'' con le quattro operazioni basilari:
 
Mostriamo un semplice esempio pratico di utilizzo della Classe ''BigInt'' con le quattro operazioni basilari:
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
  Dim s1, s2 As String
+
  Dim s1, s2 As String
  Dim addi, sott, molt, divi As BigInt
+
  Dim addi, sott, molt, divi As BigInt
 
    
 
    
 
   s1 = "9999999999999999999999999999999999999999999999999999999999999999999999999999"
 
   s1 = "9999999999999999999999999999999999999999999999999999999999999999999999999999"
Riga 25: Riga 25:
 
   Print divi
 
   Print divi
 
    
 
    
  '''End'''
+
  End
  
  
==Uso della funzione esterna ''sprintf( )''==
+
==Uso della funzione esterna "sprintf()"==
Questa modalità prevede la conversione della somma di due ''Long'' di Gambas nel formato del tipo ''unsigned long long'' <SUP>&#091;[[#Note|Nota 4]]&#093;</sup>, e, affinché possa essere rappresentato dalle risorse di Gambas, si effettuerà la conversione del risultato in una stringa (ma comunque visivamente rappresentato in forma decimale) mediante la funzione esterna ''sprintf( )'' di C.
+
Questa modalità prevede la conversione della somma di due ''Long'' di Gambas nel formato del tipo ''unsigned long long'' <SUP>&#091;[[#Note|nota 4]]&#093;</sup>, e, affinché possa essere rappresentato dalle risorse di Gambas, si effettuerà la conversione del risultato in una stringa (ma comunque visivamente rappresentato in forma decimale) mediante la funzione esterna ''sprintf( )'' di C.
  
 
Il risultato della somma dei due valori non potrà comunque superare il valore massimo rappresentabile del predetto tipo ''unsigned long long'' del linguaggio C.
 
Il risultato della somma dei due valori non potrà comunque superare il valore massimo rappresentabile del predetto tipo ''unsigned long long'' del linguaggio C.
Riga 40: Riga 40:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
  Dim l As Long
+
  Dim l As Long
  Dim p As Pointer
+
  Dim p As Pointer
 
    
 
    
  <FONT Color=gray>' ''Assegnamo alla variabile di tipo "Long" il valore massimo assegnabile per un tipo "Long" in Gambas:''</font>
+
  <FONT Color=gray>' ''Assegna alla variabile di tipo "Long" il valore massimo assegnabile per un tipo "Long" in Gambas:''</font>
 
   l = 9223372036854775807
 
   l = 9223372036854775807
 
   
 
   
 
   p = Alloc(24)
 
   p = Alloc(24)
 
   
 
   
  <FONT Color=gray>' ''Moltiplichiamo il valore della variabile per 2. Convertiamo il risultato nel tipo 'unsigned long long' del C.''
+
  <FONT Color=gray>' ''Moltiplica il valore della variabile per 2. Convertiamo il risultato nel tipo 'unsigned long long' del C.''
  ' ''Al termine convertiamo il risultato in una stringa che sarà posta mediante la funzione 'sprintf()' nell'area di memoria puntata dal 'Puntatore':''</font>
+
  ' ''Al termine converte il risultato in una stringa che sarà posta mediante la funzione 'sprintf()' nell'area di memoria puntata dal 'Puntatore':''</font>
 
   <FONT Color=#B22222>sprintf(p, "%llu", l * 2)</font>
 
   <FONT Color=#B22222>sprintf(p, "%llu", l * 2)</font>
 
   If String@(p) = "0" Then Error.Raise("Errore: è stato superato il valore massimo (18446744073709551615ULL) del tipo 'unsigned long long' del C !")
 
   If String@(p) = "0" Then Error.Raise("Errore: è stato superato il valore massimo (18446744073709551615ULL) del tipo 'unsigned long long' del C !")
Riga 59: Riga 59:
 
   Print "Risultato superiore al 'Long' ottenuto:  "; String@(p)
 
   Print "Risultato superiore al 'Long' ottenuto:  "; String@(p)
 
      
 
      
  <FONT Color=gray>' ''Liberiamo la memoria precedentemente riservata e ci assicuriamo che il Puntatore non punti ad alcuna cella utile:''</font>
+
  <FONT Color=gray>' ''Libera la memoria precedentemente riservata e si assicura che il Puntatore non punti ad alcun indirizzo rilevante di memoria:''</font>
 
   Free(p)
 
   Free(p)
 
   p = 0
 
   p = 0
 
   
 
   
  '''End'''
+
  End
  
  
 
===Caso in cui il numero è espresso in rappresentazione "binaria"===
 
===Caso in cui il numero è espresso in rappresentazione "binaria"===
Qualora il valore numerico, superiore al limite massimo rappresentabile in Gambas dal valore ''Long'', sia espresso in rappresentazione ''binaria'', si potrà adottare un'apposita funzione esterna, da noi scritta in puro C, con la quale si farà uso della funzione esterna ''strtoul( )'', dichiarata nel file header "''/usr/include/stdlib.h''". Tale funzione esterna ''strtoul( )'' converte un numero, scritto in formato stringa, in un valore numerico di tipo ''unsigned long int'' del linguaggio C <SUP>&#091;[[#Note|Nota 5]]&#093;</sup>, qualunque sia la ''base'', la quale sarà specificata nel suo terzo parametro.
+
Qualora il valore numerico, superiore al limite massimo rappresentabile in Gambas dal valore ''Long'', sia espresso in rappresentazione ''binaria'', si potrà adottare un'apposita funzione esterna, da noi scritta in puro C, con la quale si farà uso della funzione esterna "strtoul()", dichiarata nel file header ''/usr/include/stdlib.h''. Tale funzione esterna "strtoul()" converte un numero, scritto in formato stringa, in un valore numerico di tipo ''unsigned long int'' del linguaggio C <SUP>&#091;[[#Note|nota 5]]&#093;</sup>, qualunque sia la ''base'', la quale sarà specificata nel suo terzo parametro.
<BR>Il valore binario infine sarà convertito mediante la funzione esterna "''sprintf( )''" in una rappresentazione di tipo stringa, ma visivamente in forma decimale.
+
<BR>Il valore binario infine sarà convertito mediante la funzione esterna "sprintf()" in una rappresentazione di tipo stringa, ma visivamente in forma decimale.
  
 
Mostriamo un esempio pratico:
 
Mostriamo un esempio pratico:
Riga 78: Riga 78:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
  Dim bnr, rit As String
+
  Dim bnr, rit As String
 
    
 
    
 
   CreaSo()
 
   CreaSo()
Riga 91: Riga 91:
 
   Print rit
 
   Print rit
 
        
 
        
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Private''' Procedure CreaSo()
+
  Private Procedure CreaSo()
 
    
 
    
 
   File.Save("/tmp/lib.c", "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n" &
 
   File.Save("/tmp/lib.c", "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n" &
Riga 106: Riga 106:
 
   Shell "gcc -o /tmp/lib.so /tmp/lib.c -shared -fPIC" Wait
 
   Shell "gcc -o /tmp/lib.so /tmp/lib.c -shared -fPIC" Wait
 
    
 
    
  '''End'''
+
  End
 
 
  
  
  
 
=Note=
 
=Note=
[1] Come è noto, il tipo nativo ''Long'' di Gambas corrisponde sostanzialmente al tipo "''signed long int''" del linguaggio C (vedi anche il file header "''/usr/include/limits.h''").
+
[1] Come è noto, il tipo nativo ''Long'' di Gambas corrisponde sostanzialmente al tipo "''signed long int'' " del linguaggio C (vedi anche il file header ''/usr/include/limits.h'').
  
[2] Vedere anche: [[Operazioni_con_precisione_quadrupla_a_128-bit_con_numeri_in_virgola_mobile_mediante_la_libreria_quadmath.h|Operazioni con precisione quadrupla a 128-bit con numeri in virgola mobile mediante la libreria quadmath.h]]
+
[2] Vedere anche: [[Operazioni con precisione quadrupla a 128-bit con numeri in virgola mobile mediante la libreria quadmath.h]]
  
 
[3] Interessante vedere anche la libreria esterna "''[http://www.gambas-it.org/smf/index.php?topic=5589.msg41269#msg41269 BigNumber]''", autori Davide Zanin e Frhack3r.
 
[3] Interessante vedere anche la libreria esterna "''[http://www.gambas-it.org/smf/index.php?topic=5589.msg41269#msg41269 BigNumber]''", autori Davide Zanin e Frhack3r.
  
[4] Il tipo ''unsigned long long'' è specificato nel file header "''/usr/include/limits.h''".
+
[4] Il tipo ''unsigned long long'' è specificato nel file header ''/usr/include/limits.h''.
  
[5] Il tipo ''unsigned long int'' è specificato nel file header "''/usr/include/limits.h''".
+
[5] Il tipo ''unsigned long int'' è specificato nel file header ''/usr/include/limits.h''.

Versione attuale delle 16:47, 1 lug 2024

Come è noto, in Gambas il tipo di variabile Long in Gambas è capace di contenere valori positivi non superiori al numero 9.223.372.036.854.775.807. [nota 1]

Per poter ottenere dalla somma (o dalla moltiplicazione) di due o più numeri un risultato superiore al limite massimo rappresentabile in Gambas dal valore Long, si potranno adottare alcune modalità [nota 2][nota 3] che di seguito descriveremo.

Uso della Classe Classe BigInt del Componente gb.gmp

Per poter superare i limiti del suo nativo tipo Long, Gambas fornisce un apposito Componente, denominato "gb.gmp". In particolare questo Componente è costituito da due Classi: BigInt, che rappresenta un numero intero con numero potenziale illimitato di cifre, e "Rational ", dedicato alla gestione dei numeri razionali.

Mostriamo un semplice esempio pratico di utilizzo della Classe BigInt con le quattro operazioni basilari:

Public Sub Main()
 
  Dim s1, s2 As String
  Dim addi, sott, molt, divi As BigInt
 
  s1 = "9999999999999999999999999999999999999999999999999999999999999999999999999999"
  s2 = "8888888888888888888888888888888888888888888888888888888888888888888888888888"
  
  addi = BigInt.FromString(s1) + BigInt.FromString(s2)
  sott = BigInt.FromString(s1) - BigInt.FromString(s2)
  molt = BigInt.FromString(s1) * BigInt.FromString(s2)
  divi = BigInt.FromString(s1) / BigInt.FromString(s2)
  
  Print addi
  Print sott
  Print molt
  Print divi
  
End


Uso della funzione esterna "sprintf()"

Questa modalità prevede la conversione della somma di due Long di Gambas nel formato del tipo unsigned long long [nota 4], e, affinché possa essere rappresentato dalle risorse di Gambas, si effettuerà la conversione del risultato in una stringa (ma comunque visivamente rappresentato in forma decimale) mediante la funzione esterna sprintf( ) di C.

Il risultato della somma dei due valori non potrà comunque superare il valore massimo rappresentabile del predetto tipo unsigned long long del linguaggio C.


Mostriamo un esempio:

' int sprintf(char *str, const char *format, ...)
' Sends formatted output to a string pointed to, by str.
Private Extern sprintf(strP As Pointer, formatS As String, lo As Long) As Integer In "libc:6"


Public Sub Main()

  Dim l As Long
  Dim p As Pointer
 
' Assegna alla variabile di tipo "Long" il valore massimo assegnabile per un tipo "Long" in Gambas:
  l = 9223372036854775807

  p = Alloc(24)

' Moltiplica il valore della variabile per 2. Convertiamo il risultato nel tipo 'unsigned long long' del C.
' Al termine converte il risultato in una stringa che sarà posta mediante la funzione 'sprintf()' nell'area di memoria puntata dal 'Puntatore':
  sprintf(p, "%llu", l * 2)
  If String@(p) = "0" Then Error.Raise("Errore: è stato superato il valore massimo (18446744073709551615ULL) del tipo 'unsigned long long' del C !")
  
  Print "Valore massimo rappresentabile dal 'Long': 9223372036854775807\n"

  Print "Risultato superiore al 'Long' ottenuto:   "; String@(p)
   
' Libera la memoria precedentemente riservata e si assicura che il Puntatore non punti ad alcun indirizzo rilevante di memoria:
  Free(p)
  p = 0

End


Caso in cui il numero è espresso in rappresentazione "binaria"

Qualora il valore numerico, superiore al limite massimo rappresentabile in Gambas dal valore Long, sia espresso in rappresentazione binaria, si potrà adottare un'apposita funzione esterna, da noi scritta in puro C, con la quale si farà uso della funzione esterna "strtoul()", dichiarata nel file header /usr/include/stdlib.h. Tale funzione esterna "strtoul()" converte un numero, scritto in formato stringa, in un valore numerico di tipo unsigned long int del linguaggio C [nota 5], qualunque sia la base, la quale sarà specificata nel suo terzo parametro.
Il valore binario infine sarà convertito mediante la funzione esterna "sprintf()" in una rappresentazione di tipo stringa, ma visivamente in forma decimale.

Mostriamo un esempio pratico:

Library "/tmp/lib"

' char * bindecstring(const char * binario)
' Converte un numero binario in numero in rappresentazione decimale e di tipo string.
Private Extern bindecstring(binario As String) As String


Public Sub Main()
 
  Dim bnr, rit As String
 
  CreaSo()
  
' Il valore espresso in rappresentazione "binaria" da mostrare in forma decimale, ma di tipo stringa:
  bnr = "1111111111111111111111111111111111111111111111111111111111111111"
  
  rit = bindecstring(bnr)
  
  Print rit
     
End


Private Procedure CreaSo()
 
 File.Save("/tmp/lib.c", "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n" &
           "char * bindecstring(const char * binario) {\n\n" &
           "   unsigned long int ris;\n"
           "   char *rit = calloc(72, sizeof(char));\n\n" &
           "   ris = strtoul(binario, NULL, 2);\n" &
           "   sprintf(rit, \"%lu\", ris);\n\n" &
           "   return rit;\n\n}")
 
 Shell "gcc -o /tmp/lib.so /tmp/lib.c -shared -fPIC" Wait
 
End


Note

[1] Come è noto, il tipo nativo Long di Gambas corrisponde sostanzialmente al tipo "signed long int " del linguaggio C (vedi anche il file header /usr/include/limits.h).

[2] Vedere anche: Operazioni con precisione quadrupla a 128-bit con numeri in virgola mobile mediante la libreria quadmath.h

[3] Interessante vedere anche la libreria esterna "BigNumber", autori Davide Zanin e Frhack3r.

[4] Il tipo unsigned long long è specificato nel file header /usr/include/limits.h.

[5] Il tipo unsigned long int è specificato nel file header /usr/include/limits.h.