Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: antoniog - Maggio 06, 2021, 03:42:52 pm

Titolo: [RISOLTO]strano risultato di parte frazionale di un numero in stringa
Inserito da: antoniog - Maggio 06, 2021, 03:42:52 pm
Nella trasformazione  della parte frazionale di un numero in stringa Lazarus opera di fantasia o sbaglio qualcosa?
Provate ad inserire un pulsate in una form e scrivete questo codice:
Codice: [Seleziona]

procedure TForm1.Button7Click(Sender: TObject);
 var
 st : string;
 num : real;
 mNumber : double;
 begin
 mNumber:= 80237,68;
 num:=Frac(mNumber);
 St:= IntToStr(Trunc(Num * 100));
 showmessage(st);
 end; 
il risultato mi da 67 e non 68
Sono stupito ed un po anche inc...
Titolo: Re:strano risultato di parte frazionale di un numero in stringa
Inserito da: brunello - Maggio 06, 2021, 04:54:44 pm
con questa conversione il risultato è corretto, ciao
Codice: [Seleziona]
 showmessage(FloatToStrF(num * 100,  ffNumber, 10,2));
Titolo: Re:strano risultato di parte frazionale di un numero in stringa
Inserito da: antoniog - Maggio 06, 2021, 08:27:39 pm
Brunello, ringrazio per la risposta.
funziona ma a me va bene così:
Codice: [Seleziona]
showmessage(FloatToStrF(num * 100,  ffNumber, 10,0));

perchè non voglio decimali di decimali.
Avevo già risolto con:
Codice: [Seleziona]
st:=rightstr(Floattostr(mNumber),2);
showmessage(st);

Posso mettere risolto anche se le soluzioni trovate aggirano il problema.
Titolo: Re:[RISOLTO]strano risultato di parte frazionale di un numero in stringa
Inserito da: SB - Maggio 09, 2021, 08:19:31 am
...
 num:=Frac(mNumber);
 St:= IntToStr(Trunc(Num * 100));
 showmessage(st);
 end; 
..
il risultato mi da 67 e non 68
Sono stupito ed un po anche inc...

Il problema non è di FP.
Probabilmente ti sfugge che i numeri sono trattati internamente in binario, non in decimale
Non puoi pensare che i numeri reali siano esattamente ciò che scrivi nel programma, specie quando hanno una parte frazionaria
Infatti quando scrivi come double il numero 80237.68 in realtà viene memorizzato internamente
80237.679999999993
Per chi è curioso:
0100000011110011100101101101101011100001010001111010111000010100

L'uso del Trunc() invece del Round() fa il resto
Te ne puoi rendere conto seguendo i passaggi uno ad uno

Codice: [Seleziona]
 mNumber:= 80237.68;
 num:=Frac(mNumber);
 st := format('%.10f',[num]);
 showmessage(st);
 st := format('%.10f',[num*100]);
 showmessage(st);
 St:= IntToStr(Trunc(Num * 100));
 showmessage(st);
Titolo: Re:[RISOLTO]strano risultato di parte frazionale di un numero in stringa
Inserito da: DragoRosso - Maggio 09, 2021, 12:26:08 pm
Vorrei aggiungere due note a quanto già detto:


Codice: [Seleziona]

 num : real;
 mNumber : double;

1) Attenzione ai tipi, double e real potrebbero non avere la stessa precisione (15 cifre contro 7 normalmente); real è un tipo che dipende dalla piattaforma in uso. Consiglio di usare sempre tipi omogenei.

2) L'assegnazione tra tipi non omegenei impone o in fase di compilazione o in fase di runtime una conversione ---> quindi con introduzione di errori, sopratutto nei dati in virgola mobile.

Ovviamente bisogna porre attenzione nei confornti tra dati in virgola mobile (ma anche se sono interi derivati da virgola mobile  :P ), ci potrebbero essere sorprese come quelle indicate.

Saluti
Titolo: Re:[RISOLTO]strano risultato di parte frazionale di un numero in stringa
Inserito da: antoniog - Maggio 09, 2021, 11:06:04 pm
Ringrazio SB e DragoRosso per avermi rinfrescato alcune nozioni. Mi occupo da oltre 30 anni di gestionali e fortunatamente ancora oggi non soffro di un galoppante "analfabetismo di ritorno".
È praticamente impossibile un dialogo sereno fra informatici puri ed un semplice ingegnere civile quasi del tutto autodidatta in informatica che cerca le procedure e funzioni di sistema per ottenere i risultati che gli interessano cercando di non complicarsi la vita. Per esperienza la precisione che viene richiesta non va oltre i quatro decimali e quindi se ho 15 o 7 cifre posso dire che ne ho fin troppe e sono costretto ad arrotondare.
Posso andare oltre e superare quanto finora discusso con questo semplice codice:
Codice: [Seleziona]

uses fpexprpars, symbolic, math;


var
  s, st:string;
  mNum, mNumber : real;
begin
   s:='( ( 9.20*6.25 ) +9.20 *( 1.37/2 )  ) *2+ ( 10.00*6.25*2 )+( 1.00*1.35 )';
   mNumber:= RoundTo(quickevaluate(s,[],[]),-2);
   mNum:=Frac(mNumber);
   St:= IntToStr(Trunc(mNum * 100));
   showmessage(st);
   //mi darà la stringa '95' che è quello che volevo
end;
il risultato real di -s- lo posso ottenere  anche con una query:
Codice: [Seleziona]

ZQuery1.SQL.Text := 'SELECT ' + s+'*1.00' +';';
          zQuery1.Active := True;
          s:= StringReplace(zQuery1.Fields[0].Text, '.',',', [rfReplaceAll]);
          mNumber:= RoundTo(StrToFloat(s),-2);
          St:= IntToStr(Trunc(mNum * 100));
          showmessage(st); 
il segreto è RoundTo() in entrambi i casi.
Titolo: Re:[RISOLTO]strano risultato di parte frazionale di un numero in stringa
Inserito da: doc - Maggio 12, 2021, 11:06:10 am
@antoniog

Caro collega Ing., altro che computer e software....io sono cresciuto col regolo calcolatore e la precisione del metro "a bacchette" da cantiere. Bei tempi.... :'(
Titolo: Re:[RISOLTO]strano risultato di parte frazionale di un numero in stringa
Inserito da: SB - Maggio 12, 2021, 05:46:47 pm
Ringrazio SB e DragoRosso per avermi rinfrescato alcune nozioni. Mi occupo da oltre 30 anni di gestionali e fortunatamente ancora oggi non soffro di un galoppante "analfabetismo di ritorno".
È praticamente impossibile un dialogo sereno fra informatici puri ed un semplice ingegnere civile quasi del tutto autodidatta in informatica che cerca le procedure e funzioni di sistema per ottenere i risultati che gli interessano cercando di non complicarsi la vita. Per esperienza la precisione che viene richiesta non va oltre i quatro decimali e quindi se ho 15 o 7 cifre posso dire che ne ho fin troppe e sono costretto ad arrotondare.
Posso andare oltre e superare quanto finora discusso con questo semplice codice:
Codice: [Seleziona]
   mNumber:= RoundTo(quickevaluate(s,[],[]),-2);
...
   mNum:=Frac(mNumber);
   St:= IntToStr(Trunc(mNum * 100));

Codice: [Seleziona]
          mNumber:= RoundTo(StrToFloat(s),-2);
...
          St:= IntToStr(Trunc(mNum * 100));
il segreto è RoundTo() in entrambi i casi.

Perdonami, ma se i decimali sono così importanti per il tuo lavoro forse è meglio insistere su questo punto per evitarti problemi.
Ribadisco che il punto critico del tuo codice è il trunc(), che sarebbe da evitare
Qualunque cosa esca dal RoundTo() in generale non è un numero decimale esatto a due cifre, ma una rappresentazione binaria di un numero molto vicino
Non escluderei a priori l'esistenza di numeri arrotondati a 2 cifre decimali che moltiplicati per 100 e troncati siano diversi da quello che ti aspetti

Come ti ha fatto notare DragoRosso, è meglio non sottovalutare i problemi di precisione nei numeri
Le 7 o 15 cifre significative sono quelle totali, non quelle dopo la virgola, mentre tu parli di 4 cifre dopo la virgola
Nell'esempio che hai pubblicato, il numero 80237.68 usa 7 cifre significative. Sei al limite per il tipo float.
Se aggiungi 2 cifre sei già fuori precisione e necessiti di un double.

Se ho compreso la tua esigenza, che sembra simile a quella che si ha in campo economico dove si lavora con i centesimi di euro, ti consiglio di prendere in considerazione altri tipi di dati numerici.
Esistono tipi di dati che internamente lavorano direttamente con la rappresentazione decimale del numero ed evitano per quanto possibile problemi di conversione binaria
Vedi ad esempio BCD
Ovviamente hanno un costo computazionale più elevato, ma li hanno inventati proprio per gestire situazioni di questo tipo.




Titolo: Re:[RISOLTO]strano risultato di parte frazionale di un numero in stringa
Inserito da: antoniog - Giugno 12, 2021, 11:40:17 am
Caro Doc,
anch'io ho usato il regolo calcolatore ed anche le tavole logaritmiche, quando i calcoli si facevano a "spanne" stimando il risultato e spesso usando anche i prontuari Santarella e Torsello. I risultati erano attendibili senza tante scene grafiche e il calcolatore sapeva quello che faceva mentre oggi, spesso, non lo sa, inserisce alcuni dati ed ottiene il risultato, facile e pericoloso. Il computer per me è sempre stato un hobby, una passione portata avanti dalla metà degli anni '80 anche con qualche soddisfazione ma sempre e solo con la finalità di supporto ed automazione delle routine più noiose per chi sa quello che fa.
Titolo: Re:[RISOLTO]strano risultato di parte frazionale di un numero in stringa
Inserito da: antoniog - Giugno 12, 2021, 11:46:06 am
SB
grazie del consiglio, lo terrò in debita considerazione.
Titolo: Re:[RISOLTO]strano risultato di parte frazionale di un numero in stringa
Inserito da: doc - Giugno 12, 2021, 09:50:21 pm
Vedo che il problema sul formato numerico ha suscitato un bell'interesse....un pò come il "casino" che si crea quando si pretende di ottenere la massima precisione numerica nel calcolo, usando perciò il tipo Extended, ma poi ci si scorsa che compilando il tutto per Windows a 64 bit e destinazioni non Intel Extended è un alias per Double (ossia il tipo Extended viene convertito, in automatico, dal compilatore nel formato Double). A volte, nella ricerca della massima precisione nel calcolo numerico (ma non solo lì), si perde quello che è il fulcro del problema: il pc è una macchina, con delle limitazioni, che opera secondo istruzioni precise e con un suo linguaggio determinato; non pensiamo che possa essere un "cervello artificiale" in grado di pensare ed agire come il nostro.....al momento non lo fa ancora, in un futuro...mah!

Quando si scrive un programma di calcolo numerico occorre sempre pensare (almeno io faccio così) ai seguenti punti:
1) quale tipo di dato avrò in input?
2) quale è la precisione del dato di input?
3) come voglio gestire sub-dati intermedi?
4) quale tipo di dato avrò in output?
5) quale è la precisione del dato di output?

Un chiaro esempio lo si può ottenere quando ho la necessità di salvare su di un file temporaneo dei dati numerici. Quale tipo di file uso? Molti commettono l'errore, forse perchè vogliono poter leggere chiaramente cosa contiene quel file, di usare il tipo Text. Non dico che non vada bene, ma per la miseria quante volte vogliamo far fare al nostro programma la conversione numero -> stringa e viceversa? Questa continua conversione non è immune da errori.
Quindi cerchiamo di usare il tipo più adatto alle nostre esigenze ma anche il più conforme alla compilazione che vogliamo ottenere.

@ antoniog
Purtroppo i software di calcolo strutturale, sempre più orientati agli elementi finiti, sono da un lato uno strumento potentissimo (per chi conosce la teoria alla base di tale metodologia di calcolo) mentre dall'altro una fonte infinita di possibili errori di progetto (poi le cose crollano!!!). Facendo un esempio: ho visto neo-ing modellare un setto attraversato da una trave....ma quando mai una trave attraversa un setto in c.a.? Il modello numerico-matematico proposto dal programma ha portato ad una soluzione (il processo convergeva)....peccato che era sbagliata (sottostimava fortemente il momento d'incastro). Per non parlare di chi confonde le proprietà di un elemento finito con l'altro: un plane stress element viene definito da funzioni completamente diverse rispetto ad un plane strain element!!!