Newsgroup: it.comp.lang.vo-clipper
Titolo: Round() e funzione di test

Ok ragazzi.
Dopo molti giorni di prove siamo arrivati ad avere diverse versioni di
round() che sembrano funzionare in tutti i casi finora incontrati nella
discussione, ma nessuna che garantisca il funzionamento al 100%.
La necessità ora è quella di ideare un test che possa ciclare diversi
numeri.
Personalmente ritengo che non sia possibile ciclare tutte le combinazioni,
ma possiamo almeno ciclare quelle che possono verificarsi nella gestione
dell'euro.
Penso inoltre che un test completamente automatico non sarebbe affidabile.
L'unica funzione che arrotonda sicuramente sempre bene è quella implementata
nel ns. intelletto. :-)
Direi quindi che si potrebbe partire dalla funzione di test da me postata,
che confronta l'output della round di Enrico con quello della mia,
aggiungere anche le altre round (compresa quella standard di Clipper) ed
alzare i limiti dei cicli FOR per testare altre combinazioni.
Nel momento in cui il test si fermerà per evidenziare differenze tra i
diversi risultati, manualmente potremo verificare quale/i funzione/i ha dato
problemi, ed in quale situazione.
Ritengo quasi impossibile che tutte le versioni di round sviluppate finora,
che si fondano su metodi tanto diversi, diano lo stesso identico errore in
corrispondenza di qualche valore.
Certo, questo test può impiegare molto tempo, però forse potremo
suddividerci i
valori e scambiarci i risultati.
Cosa ne pensate ?
Ciao.
Davide.

Ok ragazzi.
Dopo molti giorni di prove siamo arrivati ad avere diverse versioni di
round() che sembrano funzionare in tutti i casi finora incontrati nella
discussione, ma nessuna che garantisca il funzionamento al 100%.
La necessità ora è quella di ideare un test che possa ciclare diversi
numeri.
Personalmente ritengo che non sia possibile ciclare tutte le combinazioni,
ma possiamo almeno ciclare quelle che possono verificarsi nella gestione
dell'euro.
Penso inoltre che un test completamente automatico non sarebbe affidabile.
L'unica funzione che arrotonda sicuramente sempre bene è quella implementata
nel ns. intelletto. :-)
Direi quindi che si potrebbe partire dalla funzione di test da me postata,
che confronta l'output della round di Enrico con quello della mia,
aggiungere anche le altre round (compresa quella standard di Clipper) ed
alzare i limiti dei cicli FOR per testare altre combinazioni.
Nel momento in cui il test si fermerà per evidenziare differenze tra i
diversi risultati, manualmente potremo verificare quale/i funzione/i ha dato
problemi, ed in quale situazione.
Ritengo quasi impossibile che tutte le versioni di round sviluppate finora,
che si poggiano su metodi tanto diversi, diano lo stesso identico errore in
corrispondenza di qualche valore.
Certo, questo test può impiegare molto tempo, però forse potremo dividerci i


Ok, ecco il test.
Con l'occasione ho anche ottimizzato la round3 (sempre che continui a
funzionare bene come l'altra). Ora non usa piů l'elevamento a potenza nel
caso dei decimali negativi. Enrico, puoi provare se questa č piů veloce ?
Ciao.
Davide.
STATIC FUNCTION TEST( )
     LOCAL nErr := 0
     LOCAL nTot := 0
     LOCAL CRLF :=chr(13)+chr(10)
     LOCAL i,j,nUL,cr,cr2,cr3,cr4
     nUL:=fcreate("TEST.LOG")
     If nUL==-1
       ? "Errore: Impossibile creare il file di log"
       quit
     Endif
     FOR j = -2 TO 2                     // decimali
     FOR i = -100 TO 100 STEP 0.001
         i = VAL( STR( i ) )
         ? i,j
         ? ROUND( i, j )       // Clipper
         ? ROUND2( i, j )      // Enrico
         ? ROUND3( i, j )      // Davide
         ? ROUND4( i, j )      // Diego
                               // ... fino a 24
         cr4:=SAVESCREEN(ROW()  ,1,ROW()  ,50)
         cr3:=SAVESCREEN(ROW()-1,1,ROW()-1,50)
         cr2:=SAVESCREEN(ROW()-2,1,ROW()-2,50)
         cr :=SAVESCREEN(ROW()-3,1,ROW()-3,50)
         IF (cr <> cr2) .or. (cr2 <> cr3) .or. (cr3 <> cr4)
           fwrite(nUL,"Valore:"+Str(i)+" Decimali:"+Str(j)+CRLF)
           fwrite(nUL,"Round :"+cr +CRLF)
           fwrite(nUL,"Round2:"+cr2+CRLF)
           fwrite(nUL,"Round3:"+cr3+CRLF)
           fwrite(nUL,"Round4:"+cr4+CRLF)
           // ....
           nErr++
         ENDIF
         nTot++
     NEXT i
     NEXT j
     ? "ROUND()    ", nErr, nTot, LTRIM( STR( nErr / nTot * 100 ) ) + "%"
     fwrite(nUL,"Totale:"+Str(nErr)+Str(nTot)+" "+LTRIM( STR( nErr / nTot *
100 ) ) + "%" +CRLF)
     If ! fClose(nUL)
       ? "Errore: Impossibile chiudere il file di log"
     Endif
     RETURN NIL
Function Round3(nNum,nDec)
Local cNum:=Str(nNum),cInt,cDec,i
i:=AT(".",cNum)
If i=0                                     // Se il numero S intero
  i:=Len(cNum)+1                               // aggiungo un decimale
  cNum += ".0"                                 // per le verifiche
Endif
Do Case
  Case nDec=0                              // Nessun Decimale
    cInt:=Left(cNum,i-1)                       // Parte Intera
    If SubStr(cNum,i+1,1)>="5"                 // Se Decimale successivo >=
"5" ..
      cInt:=Str(Val(cInt)+IF(nNum<0,-1,1))     // .. aumento di 1 la parte
intera
    Endif
  Case nDec<0                              // Decimali negativi
    cInt:=Left(cNum,i+nDec-1)                  // Parte Intera
    If SubStr(cNum,i+nDec,1)>="5"              // Se Decimale successivo >=
"5" ..
      cInt:=Str(Val(cInt)+IF(nNum<0,-1,1))     // .. aumento di 1 la parte
intera
    Endif
    cInt += Replicate("0",-nDec)               // aggiungo cifre tolte prima
  Otherwise                                // Decimali Positivi
    cInt:=left(cNum,i-1)                       // Parte Intera
    cDec:=PADR(SubStr(cNum,i+1,nDec),nDec)     // Parte Decimale
    If SubStr(cNum,i+1+nDec,1)>="5"            // Decimale successivo >= "5"
..
      If cDec=REPLICATE("9",nDec)              //    Se S gia 999..
        cDec:=REPLICATE("0",nDec)              //    .. i decimali vanno a
zero ..
        cInt:=Str(Val(cInt)+IF(nNum<0,-1,1))   //    .. aumento di 1 la
parte intera
      Else
        cDec:=PADL(Val(cDec)+1,nDec,"0")       //    .. aumento di 1 la
parte decimale
      Endif
    Endif
    cInt += "."+cDec
EndCase
Return Val( Space(10)+cInt )             // x allineamento

 wrote in message
9tdm8o$iel$1...@pegasus.tiscalinet.it...


 Cosa ne pensate ?
Sicuramente. Crei tu i "pacchetti" da dividere?
EMG
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg

 caso dei decimali negativi. Enrico, puoi provare se questa č piů veloce ?
Provata. Con i decimali negativi mi sembra ora la piů veloce.


 quanti italiani avrebbero approvato la pensata di faccia da mortadella.
Ah, ah, ah, e chi sarebbe questo "faccia da mortadella"? :-))) Comunque
io voto contro l'Euro al 100%. Sarebbe anche una buona cosa il ridurre
le "frontiere" tra i popoli ma il tutto si riduce, invece, solo ad una
immane operazione commerciale che, alla fine, riempirà solo le tasche
dei soliti furbi...


 suddividerci i


ammesse, in alcuni casi, anche 6 cifre decimali, dico bene?).
Mi sembra che mettere un limite al numero di cifre decimali possa
riguardare solo la fase di conversione da lire ad euro, per
l'individuazione della cifra da valutare nel caso di importi molto
bassi.
Nell'uso dell'euro, invece, si verificano casi in cui i decimali sono
ben oltre sei...
Considera 1897.36 / 2.45 ....
Invece, nel caso delle moltiplicazioni, mi pare che si arrivi ad un
massimo di 4 decimali.
ciao

 la round() e la roundw() daranno l'eventuale solito errore...
Questo è vero per tutte le funzioni proposte. Per questo il mio test prevede
di testarle tutte assieme.
Ciao.
Davide.

 Provata. Con i decimali negativi mi sembra ora la più veloce.
bene.
Grazie,
Davide.

 hanno spelato le tasche nostre per entrare in eurolandia.
Non parlo per VO, che non conosco (ho solo una vecchia versione 1.0 in un
cassetto), ma considera questa situazione in Clipper:
Un Cliente, il 01/03/2002 vende 100 portaceneri al prezzo di 5,12045 Euro
ognuno.
A fine fattura ottieni un imponibile di 512,045 Euro. Devi arrotondarlo a 2
cifre perchè è un numero da contabilizzare in primanota. La round() di
Clipper non ce la fa.
Per quanto riguarda le tasche spelate, sono daccordo con te, però ormai
siamo in ballo, e dobbiamo ballare.
Ciao.
Davide.


Per ottenere un prezzo o un importo ?
Nel primo caso, se c'è una piccola differenza bisogna renderne conto solo al
cliente (e se è trascurabile....), nel secondo caso invece si ha a che fare
con l'erario, perchè dopo dovrai pure applicarci l'IVA.
Ciao.
Davide.

> Un Cliente, il 01/03/2002 vende 100 portaceneri al prezzo di 5,12045 Euro
quindi... 9914,5737215 Lire
Ma chi e' quel furbacchione che compila un listino con 7 decimali?


basta anche che fossero solo 9914 Lire in origine (trasformalo in Euro),
comunque era solo un esempio. In realtą di casi come questi ce ne sono
parecchi.
Quel valore potrebbe anche essere una imposta, una volta applicata
l'aliquota ad un adeguato imponibile.
Ciao.
Davide.

 interesse)
Ah, ecco. Allora l'errore di cui sopra era previsto, giusto? Però ci
sono anche questi:
? ROUNDW( 1.1149999999999, 2 ) ==> 1.12 ???
? ROUNDW( -123.456, 1 ) ==> -123.50 (lo zero finale non ci vorrebbe)
? ROUNDW( 123.5, 0 ) ==> 124.00 (non ci vorrebbero i due zeri finali e
il punto decimale)


 ben oltre sei...
Infatti io sono per il funzionamento completo. A proposito: ho visto la
JROUND() che si trova su The Oasis e mi sembra interessante il fatto che
abbia utilizzato una tecnica simile alla mia. Solo che lui non aumenta
di un certo espilon il numero ma aumenta di uno la mantissa del numero
stesso (che, in realtà, era proprio quello che volevo ottenere io con il
mio EPS). Sembrerebbe una tecnica valida. Comunque la funzione non l'ho
testata. Pensate che ne valga la pena? Usa delle funzioni in C.



Purtroppo devo assentarmi fino a Giovedì sera o Venerdì.
Se hai tempo, comincia tu, poi mi fai sapere i risultati e da dove posso
continuare io.
Mi sembra che lanciando più sessioni DOS dal mio PC Win98 SE si possa far
girare diversi programmi di test senza influire in maniera troppo evidente
sulle performance dei singoli. Forse potremmo far girare più "pacchetti"
contemporaneamente, per far prima.
Ciao.
Davide.

 testata. Pensate che ne valga la pena? Usa delle funzioni in C.
Penso che sarebbe interessante.
Ciao.
Davide.

 wrote in message
3BFB78A4...@emagsoftware.it...


 ha scritto nel messaggio
news:KdOK7.3030$4M2....@news2.tin.it...


 lire cadauna.
E' successo! un cliente che vende bicchieri di plastica monouso li quotava
a 7,5 lire, ora li quota a confezioni di 100.
Ciao...
Claudio Driussi
http://www.swit.net/csoft
mailto:
cldr...@swit.net

caro enrico
grazie per la risposta
in sequenza le tue segnalazioni
? ROUNDW( 1.1149999999999, 2 ) ==> 1.12 ???
ab->togliendo un solo 9 (11 decimali) funziona regolarmente per i miei usi
di gestionale la precisione mi sembra sufficiente
? ROUNDW( -123.456, 1 ) ==> -123.50 (lo zero finale non ci vorrebbe)
ab ->ho già segnalato nel post questo problema da
sistemare (zero finali) prima di sistemarlo però desideravo essere sicuro
che gli arrotondamenti fossero accettabili
(devo anche lavorare per velocizzarla)
----------------
? ROUNDW( 123.5, 0 ) ==> 124.00 (non ci vorrebbero i due zeri finali e
il punto decimale)
ab-> come sopra
hai qualche altro arrotondamento sballato...mi sarebbe molto di aiuto
grazie e a buon rendere
andrea bruni
p.s. il formato di tutto ciò è strano perchè non ho potuto effettuare la
reply diretta dato che il server news di tiscali è in ritardo anni luce
sugli altri
ed ho taglia/incollato il tuo messaggio da un server free (più 
agg.to
) che
non mi consente il post

 contemporaneamente, per far prima.
Non penso che due programmi che girano contemporaneamente su un sistema
dotato di un solo processore possano terminare in un tempo inferiore
alla somma delle singole esecuzioni. Anzi, addirittura potrebbero
metterci di più a causa del tempo, pur minimo, necessario ai continui
switch da un task all'altro. O sbaglio?


 siamo d'accordo.
Bene... :-)))


 Penso che sarebbe interessante.
Niente da fare. L'ho provata ma non rispetta gli allineamenti ed è lenta
rispetto alle nostre...


 hai qualche altro arrotondamento sballato...mi sarebbe molto di aiuto
Eccoli:
? ROUNDW( 512.055, 5 ) ==> 512.05 ???
? ROUNDW( 9999999999.5, 0 ) ==> 9999999999.00 ???


 ha scritto nel
messaggio news:3BFCE763...@emagsoftware.it...


 NON mi saltate addosso  :-)
Ti assicuro che nessuno qui è interessato a saltare addosso a qualcun altro.
Forse ho utilizzato un esempio non troppo felice, ma il problema è reale.
Vediamo se riesco a spiegarmi meglio:
1) Supponiamo che un nostro Cliente venda diversi tipi di terra all'ingrosso
(per giardinaggio, uso edilizio, non so che altro....). Ha il magazzino
espresso in Tonnellate, perchè ne muove molta ogni anno. Un suo Cliente
viene a prelevarne un camion (3,5 Tonnellate). Una tonnellata costa 146,41
Euro (forse sto dicendo prezzi strampalati, ma nota che sono solo due
decimali).
Se la bolla riporta questi valori,  in fattura avremmo 146,41 * 3,5 =
512,435 Euro di imponibile, che la funzione round di Clipper arrotonda a
512,43 Euro, sbagliando di conseguenza anche il calcolo dell'IVA ed il
totale fattura.
Sono daccordo che l'errore è solo di pochi centesimi di Euro, ma la fattura
è errata, e come tale è contestabile dalla finanza.
2) Il Cliente di prima vende i suoi portaceneri a 5,12 Euro (come tu gli hai
suggerito di fare :-) ), ma invece di 100, ne vende 84. Allora 5,12 * 84 =
430,08 Euro di imponibile. Ora supponiamo che quei portaceneri si vendano
con l'aliquota iva al 4%. L'imposta è 430,08*0,04 = 17,2032 Euro. Ora penso
che sarai daccordo con me che abbiamo assolutamente bisogno di una funzione
round() che funzioni davvero.
Ciao.
Davide.

 switch da un task all'altro. O sbaglio?
Dal punto di vista puramente teorico sono daccordo con te, ma parlando di
S.O. di casa M$, mi lascio sempre qualche dubbio dietro. Comunque farò
qualche prova non appena rientrerò in ufficio, poi ti farò sapere.
Ciao.
Davide.

 sempre ok.
Va bene, allora aspetterò i risultati del test.


 operi per confronto ma in modo assoluto.
Capisco benissimo la tua posizione e la condivido, ma non saprei con cosa
altro confrontare una qualsiasi delle round(). Non abbiamo nulla di
"assoluto" (altrimenti non avremmo bisogno di testare queste funzioni :-) )
Ciao.
Davide.

 "assoluto" (altrimenti non avremmo bisogno di testare queste funzioni :-) )
In realtà, se ci pensi bene, noi stiamo lavorando per risolvere un
problema legato all'uso dei floating-point. Se il test lo facciamo in
riferimento ad una funzione che non li usa abbiamo almeno eliminato un
problema. Credo che l'ultima funzione che ho inviato sia abbastanza
semplice da esaminare in quanto non fa altro che affrontare
separatamente ed in modo pulito ogni caso che si può verificare.
