2012-08-13 15 views
6

In Delphi6 o in Delphi 2010, dichiarare due variabili di tipo Valuta (vtemp1, vtemp2) e fornire loro un valore di 0.09. Incorpora una delle variabili con la funzione ABS e confrontala con l'altra. Ci si aspetterebbe che il confronto produca un risultato positivo poiché l'orologio del compilatore rivela lo stesso valore per abs (vtemp1) e vtemp2. Stranamente la dichiarazione if fallisce !!!Funzione ABS non riuscita in Delphi

Note: -Questo problema è sperimentata solo quando si tratta di numero di 0,09 (che provano molti altri valori vicini hanno rivelato risultati normali) -Declaring la variabile come doppia invece di valuta, il problema cessa di esistere.

+2

non può riprodurre – kludg

+3

[Quanto è pericoloso per confrontare i valori in virgola mobile?] (Http://stackoverflow.com/questions/10334688/how-dangerous-is-it-to-compare-floating-point -valori) – valex

+0

Usa 'SameValue' da 'math' o simile. –

risposta

16

Penso che il motivo sia il tipo conversioni. La funzione Abs() restituisce i risultati real, quindi i valori variabili da currency a real. Date un'occhiata alla documentazione:

La valuta è un tipo di dati a virgola fissa che riduce al minimo gli errori di arrotondamento nei calcoli monetari . Sulla piattaforma Win32, è memorizzato come un intero a 64 bit in scala con le quattro ultime cifre significative implicitamente che rappresentano le posizioni decimali. Quando miscelato con altri tipi reali assegnazioni ed espressioni, valori di valuta vengono automaticamente divisi o moltiplicati per 10000.

quindi valuta è fisso e reale fluttua-point. Codice di esempio per la tua domanda è:

program Project3; 
{$APPTYPE CONSOLE} 

const VALUE = 0.09; 
var a,b : currency; 
begin 
    a := VALUE; 
    b := VALUE; 

    if a = Abs(b) then writeln('equal') 
    else writeln('not equal', a - Abs(b)); 

    readln; 
end. 

produce non uguale risultato, a causa delle conversioni di tipo;

orologio compilatore rivela lo stesso valore per abs (vtemp1) e vtemp2

provare ad aggiungere x : real, quindi chiamare x := abs(b);, aggiungere x agli orologi lista, selezionarlo e premere Edit watch, quindi selezionare in virgola mobile . X diventa 0.899...967.

non solo il valore 0.09 produce tale risultato. puoi provare questo codice per verificare:

for i := 0 to 10000 do begin 
     a := a + 0.001; 
     b := a; 
     if a <> abs(b) then writeln('not equal', a); 
    end; 

quindi, se hai bisogno del valore assoluto della variabile Valuta, fallo e basta. non utilizzare virgola mobile abs():

function Abs(x : Currency):Currency; inline; 
    begin 
     if x > 0 then result := x 
     else result := -x; 
    end; 
+0

Grazie per le risposte rapide, come hai sottolineato, ho usato una soluzione simile per evitare questo problema. Sebbene la spiegazione abbia senso, non è considerato un errore nell'IDE di Delphi o nel compilatore stesso? – Johny

+2

@Khatchig - formalmente che non è un bug ma un comportamento documentato ("come progettato"). Sono d'accordo che si tratta di un cattivo comportamento, e Embarcadero potrebbe risolverlo (rendere 'Abs (valuta)' restituire un tipo di valuta, non un float). – kludg

6

Un piccolo chiarimento. Il 'problema' appare se si confrontano i valori float:

var 
    A: Currency; 

begin 
    A:= 0.09; 
    Assert(A = Abs(A)); 
end; 

Questo è dovuto al fatto Abs(A) restituisce un valore float, e A = Abs(A) è implementato come un galleggiante confrontare.

non riproducesse se si confrontano i valori di valuta:

var 
    A, B: Currency; 
begin 
    A:= 0.09; 
    B:= Abs(A); 
    Assert(A = B); 
end; 

Ma il secondo campione è anche un potenziale problema perché B:= Abs(A) è internamente un galleggiante divisione/moltiplicazione per 10000 arrotondando al Currency (Int64), e dipende dalla modalità di arrotondamento FPU.


Ho creato uno qc report #107893, è stato aperto.

1

Ho appena scoperto che Delphi XE2 Abs funzione non sovraccarica il tipo di valuta.

Vedi l'Delphi XE2 docwiki

questi sono gli unici tipi supportati da abs

  • funzione Abs (X:): reale; sovraccarico;
  • funzione Abs (X:): Int64; sovraccarico;
  • funzione Abs (X:): numero intero; sovraccarico;
Problemi correlati