Newsgroup: it.comp.lang.vo-clipper
Titolo: Altra proposta di ROUND2()

Cari amici, prima che me lo diciate voi, mi sono accorto di alcuni
problemi con l'ultima proposta. Eccone una nuova su quella falsariga ma
che non fa uso (almeno esplicitamente) dell'EPS:
FUNCTION ROUND2( nValue, nDecimals )
    LOCAL cValue := STR( nValue )
    IF AT( ".", cValue ) = 0; cValue += "."; ENDIF
    RETURN ROUND( VAL( cValue + "1" ), nDecimals )
Provatela e fatemi sapere.
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

Provatela e fatemi sapere.
Ho preso la tua nuova versione (che io chiamo Round1() ) e l'ho
comparata con la Round2() di Davide e la RoundA() aggiornata (vedi a
fine pagina).
Ho controllato il range da .001 a 1000.999 (per ora) e le tre
soluzioni danno tutte gli stessi identici risultati
Ora cerco di verificare alcuni di quei numeri "critici" che sono
emersi ultimamente, e di ampliare il range di test.
Sono stanco, ma mi pare che la RoundA() debba essere provata senza
modifica alcuna, a scanso di brutte e imprevedibili sorprese.
function RoundA( nNUM, nDEC )
	LOCAL cNUM, nULT, nAPP, cAPP, nNEW
	nAPP := nNUM * 10^(nDEC+1)
	cAPP := STR( nAPP )
	cAPP := LEFT( cAPP, AT( ".", cAPP ) - 1 )
	nULT := VAL( RIGHT( cAPP, 1 ) )
	nNEW := VAL( LEFT( cAPP, LEN( cAPP ) - 1 ) )
	nNEW += IF( nULT >= 5, 1, 0 )
	nNEW := nNEW / 10^nDEC
RETURN nNEW
ciao

 RETURN nNEW
Ecco qualche problemino:
? ROUNDA( 1.11499999999999, 2 ) ==> 1.12 ???
? ROUNDA( -1.11499999999999, -1 ) ==> 0.00 (i decimali non si devono
vedere)
? ROUNDA( -123.456, -1 ) ==> -120.00 (come sopra)
? ROUNDA( 123.5, 0 ) ==> 124.00 (idem)


 ha scritto nel
messaggio news:3BF53076...@emagsoftware.it...

Scusate tutti. Non ci capisco più niente.
Ho provato col mio clipper 5.2e con la ROUND() nativa:
? ROUND( 1.11499999999999, 2 ) ==> 1.11
? ROUND( -1.11499999999999, -1 ) ==> 0
? ROUND( -123.456, -1 ) ==> -120
? ROUND( 123.5, 0 ) ==> 124
mi sembra tutto ok. O sono diventato tutto matto !?!
fatemi sapere.
Ciao,
    Fabrizio Malaguti

 mi sembra tutto ok. O sono diventato tutto matto !?!
No, no, sei ancora sano di mente. :-))) Quelli infatti sono casi in cui
la ROUND() nativa si comporta bene (mentre quella "corretta" no).
Infatti, come ho piů volte evidenziato, il problema si manifesta circa
nel 5% dei casi. Il restante 95% č a posto. Se vuoi qualche caso in cui
la ROUND() nativa si comporta male fai girare il programma di test che
ho riportato recentemente.


 Provatela e fatemi sapere.
Round2( 0 , 2 )  ==> 0,1
Faccio altri test su questa:
FUNCTION ROUND2( nValue, nDecimals )
    LOCAL cValue := STR( nValue )
    RETURN ROUND( IF( AT( ".", cValue ) = 0 ,;
                      nValue ,;
                      VAL( cValue + "1" ) ) ,;
                  nDecimals )
poi vi faccio sapere.
Ciao.
Davide.

 poi vi faccio sapere.
No, niente da fare, non funziona neanche cosě:
? ROUND2( 1.0, 2 ) ==> 1.01 ???
Let me think...



Ok, l'ho provata fino a 300.000 Euro con tutti i millesimi. Ci ha impiegato
diverse ore su un Pentium III 800, ma non ha dato nessun errore.
Secondo me funziona bene, comunque riporto di seguito il programma di test.
Se qualcuno ci vede qualche buco...
L'unica cosa che posso aggiungere è che se commento la riga che fa " i =
VAL(STR(i)) ", il test fallisce quando arriva a 512,045 . Da li in poi tutti
i millesimi=5 falliscono. Evidentemente c'è un errore dovuto anche al
semplice incremento della variabile nel ciclo FOR.
Non solo, se nella INT() invece di aggiungere .5001 si aggiunge solo .5 , si
nota che il test fallisce di nuovo, quindi c'è un errore anche nella
moltiplicazione del numero * 100 (dato che sembra che la INT() funzioni
bene).
A questo punto direi che si può evere la certezza di ottenere un numero
(frazionario) esatto solo se lo si arrotonda dopo averlo calcolato.
Ciao.
Davide.
STATIC FUNCTION TEST( nTipo )
     LOCAL nErr := 0
     LOCAL nTot := 0
     LOCAL i
     FOR i = 0 TO 300000 STEP 0.001
         i = VAL( STR( i ) )      // Se remmo questa, il test non funziona.
         ? i
         IF ROUND2( i, 2 ) <> INT( i * 100 +.5001 ) / 100
                 ? "Errore",i,round2(i,2),INT( i * 100 +.5001 ) / 100
                 ACCEPT "" TO TASTO
                 nErr++
         ENDIF
         nTot++
     NEXT
     ? "ROUND()    ", nErr, nTot, LTRIM( STR( nErr / nTot * 100 ) ) + "%"
     RETURN NIL

 (frazionario) esatto solo se lo si arrotonda dopo averlo calcolato.
Questo era chiaro fin dall'inizio. E' uno dei problemi ben conosciuti
dei numeri floating-point. Per questo a volte si utilizzano i
fixed-point, quando la precisione è questione di vita o di morte. In
tali situazioni (quando sono coinvolte vite umane) l'utilizzo dei
floating-point non è accettabile.



Sei sicuro ?, secondo me il numero arrotondato con la INT() è ok perchè
l'errore generato dalla moltiplicazione * 100 è molto piccolo.
Comunque se sbaglio c'è un problema anche nella round2, perchè tornano gli
stessi risultati (da 0.000 a 300000.000 step 0.001). Speriamo di no.
Ciao.
Davide.

 stessi risultati (da 0.000 a 300000.000 step 0.001). Speriamo di no.
Spiegati meglio perché non ho capito.


 Spiegati meglio perché non ho capito.
Nel mio test: Round2(....)  = INT(.....)/100
Se non funziona INT() (ma io credo di si) , non funziona neanche round2()
(ma io credo sempre di si, almeno per i numeri ciclati nel test)
Ciao.
Davide.

 soluzioni che già abbiamo. Comunque, se vuoi, eccola.
Purtroppo ho trovato subito un errore alla prima prova:
? ROUNDINT( 512.055, 2 ) ==> 512.05 ???
E non va, come dicevi, neanche l'allineamento. Ecco altri problemi:
? ROUNDINT( 8.075, 2 ) ==> 8.07 ???
? ROUNDINT( -123.456, -1 ) ==> -11 ??? (l'avevi detto)
? ROUNDINT( -123.456, 1 ) ==> -123.4 ???
Tutto questo penso dipenda non dalla INT() in se ma dai calcoli che
vengono fatti nella funzione.


 Purtroppo ho trovato subito un errore alla prima prova:
Meglio concentrarci sulle altre soluzioni.
Ciao.