Può il prezzo != prezzo ?

 

Sto cercando di capire qualcosa di strano che sto vedendo in modo da poter meglio aggirare il codice in futuro.

Ho notato qualcosa di strano con uno dei miei indicatori, non stava facendo quello che avrebbe dovuto, così ho controllato il codice e sembrava corretto. Così ho fatto una piccola indagine e ho finito per creare un piccolo indicatore di prova.

Essenzialmente questo sembra essere vero . . .

double TestValue = iClose(NULL, 0, 0);
   
if(TestValue != NormalizeDouble(TestValue, Digits) )

. . . qualche idea su come questo accada?

 
Domande e risposte precedenti
 
RaptorUK:

. . qualche idea su come questo accada?

Dipende dal funzionamento interno di NormalizeDouble(). Per esempio...

   double TestValue = 1.57373;
   if (TestValue != NormalizeDouble(TestValue, 5)) MessageBox("WTF?");

Stessi risultati, per inciso, se fate quanto segue:

   double TestValue = StrToDouble("1.57373");
   if (TestValue != NormalizeDouble(TestValue, 5)) MessageBox("WTF?");

Dopo l'assegnazione iniziale, TestValue = 1.5737300000000001. NormalizeDouble(..., 5) su questo produce 1.5737299999999999.

 
WHRoeder:
Domande e risposte precedenti
Con tutto il rispetto, non penso che quel post risponda al mio problema in questo thread.
So che ci sono altri modi per farlo che NormalizeDouble . . . quello che non capisco è perché iClose sta restituendo un valore che non è già normalizzato . .
 
jjc:

Dipende dal funzionamento interno di NormalizeDouble(). Per esempio...

Stessi risultati, per inciso, se fate quanto segue:

Dopo l'assegnazione iniziale, TestValue = 1.5737300000000001. NormalizeDouble(..., 5) su questo produce 1.5737299999999999.


Quindi come faccio a far sì che TestValue sia uguale a 1.57373 e non > o < ?
 
RaptorUK:

Quindi come faccio a far sì che TestValue sia uguale a 1.57373 e non > o < ?
Nel caso non sia già chiaro, 1.57373 non può essere rappresentato esattamente come un valore in virgola mobile. Lo stesso vale per valori come 0,1. L'unica stranezza è che NormalizeDouble() finisce per usare un'approssimazione diversa da altre parti del linguaggio MQ4.
 
jjc:
Nel caso in cui questo non sia già chiaro, 1,57373 non può essere rappresentato esattamente come un valore in virgola mobile. Lo stesso vale per valori come 0,1. L'unica stranezza è che NormalizeDouble() finisce per usare un'approssimazione diversa da altre parti del linguaggio MQ4.

Ah . . no non era chiaro . . non lo sapevo. Grazie, indagherò.
 
RaptorUK:
Ah . . no non era chiaro . . non lo sapevo. Grazie, indagherò.

I valori in virgola mobile e l'aritmetica sono veloci, perché c'è il supporto per loro costruito proprio nel processore del computer, ma con il compromesso che alcuni valori non possono essere rappresentati con precisione in una variabile in virgola mobile. (Per un esempio delle implicazioni della velocità, vedere https://www.mql5.com/en/forum/116228/page2#156859).

In effetti, qualsiasi cosa che coinvolga i doppi può introdurre una sorta di errore di arrotondamento. Questo porta ad ogni sorta di stranezze divertenti. Per esempio 0.1 * 10 = 1.0, ma 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 != 1.0

Il risultato è che NormalizeDouble(x, y) non è esattamente sinonimo di Round(x, y). NormalizeDouble() restituisce l'approssimazione in virgola mobile più vicina possibile al valore arrotondato. Se fate NormalizeDouble(a, n) == NormalizeDouble(b, n) allora state fondamentalmente dicendo "a e b sono uguali, tenendo conto del fatto che l'aritmetica in virgola mobile può introdurre differenze di arrotondamento a più di n posizioni decimali?

Come molte persone hanno detto, NormalizeDouble(a, 5) == NormalizeDouble(b, 5) è quindi in effetti equivalente a MathAbs(a - b) < 0.00001, e quest'ultimo viene eseguito leggermente più velocemente. Quest'ultimo è anche comune perché è ampiamente usato in linguaggi/piattaforme che non forniscono un equivalente pratico alla funzione NormalizeDouble(). Ma la differenza di prestazioni è così minuscola che mi atterrei a NormalizeDouble() se ritenete che renda il vostro codice più leggibile.

Tutto questo è perfettamente normale per i linguaggi che hanno un tipo di dati doppio. La parte che introduce qualche stranezza proprietaria e tipica di MQ4 è che 1.57373 != NormalizeDouble(1.57373, 5). È perverso che dichiarando la costante 1.57373 e usando NormalizeDouble() si scelgano diverse approssimazioni in virgola mobile del valore.

 

Grazie :-)

Ero consapevole del problema ma non del motivo e quindi non del tutto consapevole delle possibili implicazioni.

 
tranne che con lo zero non confronta mai i doppi per l'uguaglianza
if (a > b)
if (a - b > Point / 2.)
if (a >= b)
if (a - b > -Point)
if (a != b)
if (MathAbs(a - b) > Point / 2.)
 
WHRoeder:
tranne che con zero non confronta mai i doppi per l'uguaglianza


Ho poco più di un centinaio di righe di codice in cui sto facendo esattamente questo . . . e ho usato NormalizeDouble su quasi tutto in vista per farlo funzionare in modo affidabile. Capisco l'idea dietro i tuoi suggerimenti, grazie, ma penso che possano avere un effetto negativo sulla leggibilità del mio codice e quindi sulla facilità di modifica in futuro.

Modificherò questo blocco di codice in un futuro non troppo lontano per farlo funzionare con timeframe diversi da quello del grafico su cui viene eseguito. Quando lo farò, ho intenzione di eliminare il NormalizeDoubles e sostituirlo con qualcos'altro... non sono ancora sicuro al 100%, forse una conversione in numeri interi prima del confronto...

Grazie per l'aiuto, come al solito :-)