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

Da Gambas-it.org - Wikipedia.
(Creata pagina con "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>[...")
 
Riga 63: Riga 63:
 
   p = 0
 
   p = 0
 
   
 
   
'''End'''
 
 
 
==Uso di un'apposita funzione esterna da noi scritta==
 
Si potranno adottare almeno due modalità facendo uso di apposita funzione esterna, da noi scritta in C, contenuta in una libreria dinamica condivisa .so .
 
 
===Uso della funzione esterna ''strtoul( )'' all'interno di una più ampia funzione da noi scritta===
 
La funzione esterna ''strtoul( )'', dichiarata nel file header "''/usr/include/stdlib.h''", 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'', e che sarà specificata nel suo terzo parametro.
 
 
La libreria esterna, da noi scritta, sarà davvero utile, se sarà capace di ritornare un valore superiore a quello massimo supportato dal tipo ''Long'' di Gambas. Il valore ritornato, comunque, sarà di tipo ''Stringa''.
 
 
Mostriamo un esempio pratico, nel quale la funzione esterna, da noi scritta, sommerà due valori: uno pari al valore massimo supportato dal tipo ''Long'' di Gambas e l'altro inferiore di una unità al valore massimo supportato dal tipo ''Long'' di Gambas, e ritornerà in formato stringa il valore massimo supportato dal tipo ''unsigned long int'', dichiarato nel file header "''/usr/include/limits.h''", pari a: 18446744073709551615 .
 
Library "/tmp/lib"
 
 
<FONT Color=gray>' ''char * ultrasomma(const char * valore1, const char * valore2)''
 
' ''Somma due numeri di entità fino al massimo del tipo "Long" di Gambas.''</font>
 
Private Extern ultrasomma(valore1 As String, valore2 As String) As String
 
 
 
'''Public''' Sub Main()
 
 
  Dim l1, l2 As String
 
  Dim s As String
 
 
 
  CreaSo()
 
 
 
  l1 = "9223372036854775808"
 
  l2 = "9223372036854775807"
 
 
 
  s = ultrasomma(l1, l2)
 
 
 
  Print s
 
 
 
'''End'''
 
 
 
'''Private''' Procedure CreaSo()
 
 
 
  File.Save("/tmp/lib.c", "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n" &
 
            "char * ultrasomma(const char * valore1, const char * valore2) {\n\n" &
 
            "  unsigned long int ris;\n" &
 
            "  char *rit = calloc(72, sizeof(char));\n\n" &
 
            "  ris = strtoul(valore1, NULL, 10) + strtoul(valore2, 0, 10);\n" &
 
            "  sprintf(rit, \"%lu\", ris);\n\n" &
 
            "  return rit;\n\n}")
 
 
  Shell "gcc -o /tmp/lib.so /tmp/lib.c -shared -fPIC" Wait
 
 
 
 
  '''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 convertirà tale valore in una rappresentazione di tipo stringa, ma visivamente in forma decimale (analogamente a come nei precedenti paragrafi).
+
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.
  
 
Mostriamo un esempio pratico:
 
Mostriamo un esempio pratico:

Versione delle 19:44, 7 giu 2017

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à che di seguito descriveremo. [Nota 2][Nota 3]

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
 
' Assegnamo alla variabile di tipo "Long" il valore massimo assegnabile per un tipo "Long" in Gambas:
  l = 9223372036854775807

  p = Alloc(24)

' Moltiplichiamo 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':
  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)
   
' Liberiamo la memoria precedentemente riservata e ci assicuriamo che il Puntatore non punti ad alcuna cella utile:
  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".