Newsgroup: it.comp.lang.delphi
Titolo: EURO:Tipo Currency per eliminare problemi precisione finita

Ciao a tutti.
Sono una new entry del ng: ho letto un vecchio messaggio di Zortek che
faceva riferimento al tipo Currency di Delphi. Io sviluppo in Delphi 4 un
gestionale che usa un db oracle (v.8) e ho il problema di gestire i campi
che rappresentano un importo in euro. Mi spiego: i campi sono number(15,2)
(cioč, semplificando per chi non conoscesse oracle: 2 cifre decimali) perché
devono memorizzare anche i centesimi di euro. Quando li leggo da Delphi li
metto in una variabile reale, diciamo un extended o anche solo un double:
var
  x:extended;
begin
  x:=Query.fieldbyname('NomeCampo').AsFloat;
  ..
end;
E mi becco tutti i terrificanti problemi legati alla precisione finita! Non
vi scrivo esempi perché se ne possono creare a centinaia senza nessuna
fatica..
Alcune delle soluzioni che ho preso in considerazione analizzandone l'
effettiva fattibilitŕ (anche in relazione alle mie esigenze) sono:
- utilizzare campi Oracle "interi", cioč number(15,0), in cui memorizzare i
valori moltiplicati per 100 e poi trattarli a codice;
- utilizzare campi Oracle "reali", cioč number(15,2), ma trasformarli in un
int64 al momento della lettura da database, quindi trattarli a codice;
- Effettuare tutte le operazioni trattando i numeri come stringhe (e uscendo
pazzo.)
- Fare i calcoli a mano su un foglio di carta (sono laureato in matematica:
dovrebbe riuscirmi benino..) votandomi a San FloatingPoint
Ho letto l'Help su questo tipo Currency ma non ho minimamente capito come
usarlo: se qualcuno mi scrive due righe d'esempio per tirar su il mio campo
Oracle con due decimali lo ringrazierň a vita. Se faccio
fieldbyname('NomeCampo').AsCurrency che accade? Boh, insomma per gli esperti
non sembra un quesito difficile, spero qualcuno mi risponda magari con due
righe di codice esempio (confido QUANTO MENO in Zortek!).
Grazie in anticipo.
Ah, tutto questo senza considerare che molto spesso uso le funzioni di SQL e
sono pressoché rovinato:
Query.sql.add('select sum(NomeCampo) as Totale from NomeTabella');
x:= Query.fieldbyname('Totale').AsFloat;
Supponendo di avere 501 record tutti con NomeCampo=99999999999.99, si ha
Totale= 50099999999995,0016 invece del corretto 50099999999994,99.
PAOLO
P.S.(un'ultima cosa che non c'entra niente con quanto detto sinora: ho letto
sul ng qualcuno che prendeva in giro Delphi perché creava eseguibili
 "grossi", ADDIRITTURA 700k!!! Ecco, se qualcuno mi puň spiegare come fate a
rimanere entro i 700k..  I miei meno di 1,7Mb non ci pensano proprio! Sono
io che faccio programmi complessi o sto infilando nei miei exe roba
assolutamente inutile?!?!?!?)

 assolutamente inutile?!?!?!?)
Beh se arrivi a quelle dimensioni, mi pare sicuro che ci metti dentro un po'
di grafica (icone, bitmap, o altro).. In caso contrario, non saprei proprio
perche'! Se ci metti della grafica, allora e' normale, e tra l'altro e'
anche inutile tirarla fuori, perche' dentro o fuori la devi memorizzare :-)
Per rimpicciolire i tuoi exe dopo averli compilati, usa UPX, un eccellente
compressore di file exe (ti toglie un 60,70% buono). I tuoi file restano exe
e si autoscompattano in maniera trasparente.
per info:  
http://upx.tsx.org
--
{MSX}  -  
http://msx.rules.it
Mantenitore delle FAQ di it.comp.lang.delphi,
reperibili qui: 
http://gpi.infomedia.it/abc/delphi/FaqDelphi.txt

Non avendo mai avuto a che fare con Oracle non ho idea di come memorizzi i
dati nel database (mantissa+esponente, oppure cifra per cifra?). Per andare
sul sicuro io memorizzerei tutto come intero (es. 123.45 euro lo memorizzo
come valore intero 12345) e quando lo ripesco dal database lo assegno ad una
variabile currency dividendolo per 100 e da qua in poi lo tratto come
currency. Al momento di salvarlo nel database si fa l'operazione inversa (si
moltiplica per 100 la variabile currency e si memorizza come intero).
Il tipo currency e' memorizzato cifra per cifra, per questo non e' soggetto
ad errori di arrotondamento in seguito alle operazioni aritmetiche, a
differenza dei tipi reali, memorizzati con mantissa ed esponente.
Ciao, Sandro

 ed esponente.
Semplicemente il Currency č un Int64 che viene considerato come un 
numero reale pari ad un decimillesimo del valore intero, quindi un reale 
a virgola fissa. Anche VB fa cosě, e credo qualsiasi software 
finanziario (5 cifre decimali dovrebbe essere lo standard mondiale del 
cambio di valuta)

 Ciao, Sandro
Vi ringrazio per le informazioni sui currency.
Tutti, non solo in questo thread, parlate del tipo currency come della
somma soluzione, ammirati ne tessete le lodi e incantati ne
evidenziate i pregi. Io vi credo e me ne compiaccio&#8230; ma a me
questo tipo pare risolva davvero il giusto!!! Considerando la vostra
unanime eccezionale stima del currency, deduco  che evidentemente sto
sbagliandone l&#8217;uso o non ne sto comprendendo le potenzialitŕ! Vi
prego dunque di aiutarmi di nuovo:
il mio problema giŕ lo sapete, vi scrivo i tentativi e il loro
risultato:
__________________________
procedure TForm1.Button1Click(Sender: TObject);
const
  SOMMA=50099999999994.99;
var
  i:word;
  xc,yc:currency;
  query:Tquery;
begin
  query:=TQuery.create(application);
  query.databasename:='investimenti';
  query.sql.add('select * from paolo');
  query.open;
  xc:=query.fieldbyname('campo3').value; {nel db oracle il campo (di
tipo number(15,2)) č valorizzato con il valore 99999999999,99}
  //se lo tiro su &#8220;.AsCurrency&#8221;  invece che
&#8220;.value&#8221; NON CAMBIA NULLA!
  query.close;
  query.free;
  yc:=0;
  for i:=1 to 501
  do
    begin
      yc:=yc+xc;
    end;
  edit1.text:=floattostr(yc);
  if yc-SOMMA=0
  then edit2.text:=floattostr(yc)
  else edit2.text:=floattostr(yc-SOMMA);
end;
Alla fine yc vale 50099999999994,5 invece del valore corretto
50099999999994.99.
__________________________
procedure TForm1.Button1Click(Sender: TObject);
const
  SOMMA=50099999999994.99;
var
  i:word;
  xc,yc:currency;
  query:Tquery;
begin
  query:=TQuery.create(application);
  query.databasename:='investimenti';
  query.sql.add('select * from paolo');
  query.open;
  xc:=query.fieldbyname('campo4').ascurrency/100; {nel db oracle il
campo (di tipo number(15,0)) č valorizzato con il valore
9999999999999}
  //oppure xc:=query.fieldbyname('campo4').value;  NON CAMBIA NULLA!
  query.close;
  query.free;
  yc:=0;
  for i:=1 to 501
  do
    begin
      yc:=yc+xc;
    end;
  edit1.text:=floattostr(yc*100);
  if yc*100-SOMMA=0
  then edit2.text:=floattostr(yc)
  else edit2.text:=floattostr(yc*100-SOMMA);
end;
Alla fine yc vale 50099999999994,496 invece del valore corretto
50099999999994.99.
______________________
Ma allora come lo uso questo risolutivo tipo currency?!?!?!
Tnx2Everybody,
PAOLO