Newsgroup: it.comp.lang.vo-clipper
Titolo: roundw2 altro metodo....sembra funzionare

ho ripreso un idea del grande EMG
che aveva (secondo me) il difetto di aggiungere valori indiscriminatamente.
La mia idea č di aggiungere un valore minimo
alla round() per l'arrotondamento e poi  toglierlo
per non creare 'accumuli'
mettendo il valore minimo in una variabile globale si potrebbe anche
determinare il livello di precisione
prg per prg...
di seguito la funzione che ai miei test si comporta come la roundw() ma che
č piů veloce e non sembra risentire degli stessi problemi...
saluti a tutti
andrea bruni
p.s. se il tutto da buoni risultati ho intenzione di effettuare un
operazione di 'chirurgia' togliendo dalla libreria round()
rinominandolo roundxx()
e mettendo l'obj di roundw2() (chiamandolo round())
nella libreria stessa
...la follia č alle porte....
------------------------------------------------
function roundw2
parameters cifra,dec
set deci to dec
set fixed on
ccc=if(cifra<0,-.000000000001,.000000000001)
ccc=round(cifra+ccc,dec)-ccc
set fixed off
return(ccc)
--------------------------------------------------------

 ..(megacut)
Purtroppo non sembra funzionare.
roundw2(1.114999999999,2) = 1.1200000000 ??!
Inoltre:
 Con l'ultimo test di EMG  dà il 99% di errori !!
Con decimali negativi va in errore (dovuto a SET DECIMAL TO)
Non ritorna i decimali formatati correttamente (aggiunge zeri non richiesti)
A mio avviso comunque, qualunque funzione che coinvolga numeri
floating point non potrà mai soddisfare la totalità dei casi, perchè
l'errore
stesso è insito nella scomposizione del numero originale in
mantissa+esponente
propria dell'aritmetica floating point.
Ciao
Paolo R.
paolo....@soft-com.it
www.soft-com.it

 ha scritto nel messaggio
news:RcLL7.12731$4M2.3...@news2.tin.it...


....(megacut)
E' vero che la precisione può essere variata , però
prendendo come esempio l'impostazione attuale (ccc=.000000000001)
arrotondando un numero con 12 decimali  del tipo
 xxx,xx4999999999 a 2 decimali la tua funzione sbaglierà sempre
perchè in realtà si ritroverà a fare round(xx,xx5000000000,2)
e arrotonderà sempre in eccesso la 2.a cifra !!
Variando la precisione di ccc si varierà dunque solo il numero dei 9
necessari a provocare l'errore.
Tieni conto che anche se ad un primo esame l'errore può risultare marginale
potresti trovarti in una situazione tipo roundw(<expr>,2), dove non puoi
sapere a priori quanti decimali avrà il risultato di <expr> e ti potrai
ritrovare
in un caso come sopra descritto, sbagliando il 2.o decimale.
Spero di essere stato chiaro.
Questo è il motivo per cui EMG ed io stiamo cercando una soluzione
che non coinvolga operazioni numeriche.


 ...la follia è alle porte....
No, l'dea sarebbe buona. Ma purtroppo la funzione ROUND() è "immersa" in
un modulo chiamato OPS e non credo possa essere sostituita singolarmente
(a meno di non intervenire a mano nel codice binario).
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

 propria dell'aritmetica floating point.
Può essere, ma questo lo dobbiamo ancora dimostrare.


 indicare 12.10  che 12.1
Si, certo. Il problema è che la tua funzione ne aggiunge molti altri. E'
vero che normalmente uno usa la TRANSFORM() per limitare il numero di
cifre decimali a due, però dato che ci sono delle alternative che
sembrano altrettanto valide non vedo perché accontentarsi.


 che non coinvolga operazioni numeriche.
Si, solo una cosa: sei riuscito a trovare anche un solo caso in cui la
mia ROUND2() sbaglia? Te la riporto nel caso ti fosse sfuggita:
FUNCTION ROUND2( nValue, nDecimals )
    LOCAL cValue := STR( nValue )
    IF AT( ".", cValue ) = 0; cValue += "."; ENDIF
    cValue += REPLICATE( "0", nDecimals - LEN( cValue ) + AT( ".",
cValue ) )
    RETURN ROUND( VAL( cValue + "1" ), nDecimals )


 .....
Guarda Enrico, a dire la verità mi era sfuggita perchè ho perso un pò
di msg del newsgroup, ed è vero che, per le prove che ho potuto
fare, non sembra presentare nessun problema, però mi sembrava
che la soluzione cercata dovesse essere esaustiva e non coinvolgere
operazioni o funzioni numeriche che possono ingenerare altri errori.
Solo così ha senso quello che abbiamo fatto, altrimenti teniamo buona
la tua che sicuramente è più veloce.


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

 nuova round() (la round2() all'interno...
perchè non usare semplicemente #translate ?
Ciao.
Davide.

 operazioni o funzioni numeriche che possono ingenerare altri errori.
se è solo per questo, forse hai perso anche la mia round2 con le stringhe,
dove l'unica operazione numerica è +1 o -1 su un numero intero, che non
dovrebbe dare errori di sorta.
Fino ad ora si è comportata bene nei test, e credo che l'ultima volta che
l'ha vista Enrico, abbia detto che era la più veloce (tra quelle che usano
un metodo diverso dalla sua con l'EPS dinamico ovviamente).
Prova darci un'occhiata, e se ci vedi qualcosa di strano, fammi sapere.
Ciao.
Davide.
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

 operazioni o funzioni numeriche che possono ingenerare altri errori.
Vero. Ma se non puoi dimostrare che l'uso delle operazioni numeriche
causa errori allora anche una funzione come la mia potrebbe andare
benissimo. Il succo del discorso è che non dobbiamo continuare a
lavorare sul "fumo", ci vogliono fatti concreti. Ed uno di questi mi
sembra quello scoperto da Davide (sul quale sto riflettendo) che
l'errore si manifesterebbe solo in determinate situazioni...


 nuova round() (la round2() all'interno...
Oh, se ci riesci facci sapere la procedura esatta, mi raccomando.



Ne avevamo già parlato: perché con il #translate non vengono corrette le
chiamate alla ROUND() eventualmente presenti in codice non sotto il
nostro controllo (funzioni della libreria del Clipper o di librerie
esterne).


 esterne).
La cosa si poteva risolvere semplicemente, visto che la presenza della 
direttiva del preprocessore rendeva ricursiva la chiamata alla round2,
bastava non includere la direttiva nel sorgente che eseguiva la chiamata.
Non ricordo esattamente i termini ma non mi sembrava difficile, se 
qualcuno ritrova il messaggio ci possiamo provare.
Ciao...
Claudio Driussi
http://www.swit.net/csoft
mailto:
cldr...@swit.net

 qualcuno ritrova il messaggio ci possiamo provare.
E' molto semplice: basta mettere la #translate nel proprio sorgente
(direttamente o, meglio, tramite un #include) e definire invece la
funzione in un PRG a parte che non includa tale #translate (io ho fatto
proprio così). Solo che non era questo il problema che cercavo di
evidenziare sopra. Così facendo uno sostituisce automaticamente tutte le
chiamate alla ROUND() in tutti i sorgenti che ricompila e che includono
la direttiva #translate. Ma che dire delle chiamate alla ROUND()
presenti in funzioni di libreria che non possiamo ricompilare? Spero che
ora sia più chiaro ciò che intendevo...
