Librerías: Math Utils - página 6

 
Si necesita una función personalizada para obtener exactamente la misma cadena más corta que el molde (cadena)dbl, utilice la función Repr() de la biblioteca:

cadena cadena_más_corta = Repr(dbl) .

Esta función fue una vez necesario antes de que los desarrolladores MQL corregido el error con la cadena y Print() para ajustarse a la norma ieee-754.
 

Ojalá tuvieras razón y fuera así de sencillo. No estaría aquí si fuera tan fácil y definitivamente no perdería tantas horas de trabajo en esto.


Es cierto que necesito

1. controlar el número de dígitos después del punto decimal

2. ajustar dinámicamente el número de dígitos y hacerlo lo más corto posible


Mis dobles vienen de

Tickvalue -> SYMBOL_TRADE_TICK_VALUE

TickSize -> SYMBOL_TRADE_TICK_SIZE

y

LotValue = ((TickValue / TickSize) * lote);


Nada extraño, valores estándar, todo bien, pero LotValue parece ser difícil de formatear y mostrar en pantalla.


El GRAN problema es que mis dobles muestran como 1.000000000 pero en realidad son 1.000000001

(Sé cómo funcionan los dobles, y entiendo que es normal)


Print(), DoubleToString(), NormalizeDoubles() y StringFormat() básicamente redondean el número y el número resultante es terriblemente erróneo; nada funcionó, la precisión deseada simplemente no se pudo conseguir con las funciones MQL4 porque redondean el número, y 1.000000000 acabó siendo igual a 1.1

(no se me ocurre ninguna circunstancia en la que sea conveniente para una aplicación que muestra constantemente Precios ver un número 'falseado' transformado de 1.04966 a 1.0497 pero esa es una discusión para otro día)


Por eso al principio utilizaba una fórmula sencilla para conseguir la precisión deseada

int p = 5; // precisión deseada

double n = 1.000000000;

double p10 = (p * 10);

double(long(n * p10) / p10);

Pero la cosa se complica cuando en vez de Forex, es Crypto donde necesito una precisión mayor de 9-10, y por encima de eso no era capaz de eliminar ceros finales, así que llegué a tus funciones.

Y todo este problema porque necesito dar al usuario la mayor información posible y el espacio en pantalla es limitado, por eso necesito apretar el número en un espacio fijo.


Tu función Trunc() hace el truco para el 99,9% de los números, pero hay algunos que no cooperan y necesitan un tratamiento especial.

Esperaba que pudieras darme una fórmula reducida para hacerlo.


Y ahora añadiendo a mis problemas la función Round(double, int) detiene la ejecución de MT4 con algunos dobles. No puedo entender por qué, el doble no es tan grande, siendo 100000.0000000000

Es un número común que representa el valor de 1 Lote para EURUSD, y si escribo a mano el valor todo está bien, pero si viene de las matemáticas LotValue = ((TickValue / TickSize) * lote); MT4 se bloquea.


Una tarea tan sencilla y ya me he pasado más de 40 horas en esto. ¡Me está matando!

 
Cristian Dan Fechete #:

Es cierto que lo necesito:

1. controlar el número de dígitos después del punto decimal

2. ajustar dinámicamente el número de dígitos y hacerlo lo más corto posible


Le dije
doble n = 1.000000000;
Es lo mismo que:
double n = 1.0;

Tu requisito:
decimales en la cadena <= dígitos_especificados

Si su único requisito es formatear el número a una cadena lo más corta posible sin 0 al final (controlando al mismo tiempo el número máximo de dígitos decimales):

string s1 = (string) Round(number, digits);

string s2 = (string) NormalizeDouble(number, digits);

string s3 = StringFormat("%.5f", number);
Elija cualquiera de ellos.

Round, y NormalizeDouble controlarán el máximo de dígitos decimales. Entonces, convirtiendo a cadena (cadena)dbl obtendrá la cadena más corta posible sin los ceros finales. StringFormat() hace lo mismo, pero parece ser un poco más lento si se llama millones de veces en tu código.

En su caso, DoubleToString() no es aconsejable ya que rellenará las cadenas más cortas < dígitos con ceros al final para mantener el número fijo de dígitos decimales. Eso no es lo que usted pide. Usted pide un número dinámico de dígitos decimales (el más corto).

Editar:
Calculas mal la precisión como
int p = 5; // precisión deseada
double p10 = (p * 10);

Debería calcularse como
int p = 5; // precisión deseada
double p10 = MathPow(10, p);

 

Parece que después de 4 mensajes no fui capaz de hacerte entender mi problema, y me siento terriblemente decepcionado de mi fracaso.

Y el estilizador de este sitio está completamente estropeado, por lo que lleva mucho tiempo escribir correctamente un mensaje aquí

double n = 1.000000000; 
should be the same as:
double n = 1.0;
but it is NOT

No puedo explicar por qué, pero hay que suponer que 1.000000000; tiene un decimal distinto de 0 en alguna parte, aunque gráficamente no he sido capaz de mostrarlo.

Pero los resultados son esos

string s1 = (string) Round(number, digits);  -> blocks MT4

string s2 = (string) NormalizeDouble(number, digits); -> returns a 'faked' string where a rounding is done on last digit

string s3 = StringFormat("%.5f", number); -> same as NormalizeDouble()

para números como 19.65400

string s = (string) Trunc(number, digits);

funciona perfectamente. Y si introduzco manualmente 1.0000000; sigue funcionando perfectamente.

Para que me entiendas, uso la función sobre más de 400 parámetros diferentes y cada uno de ellos tiene un valor diferente en cada tick y Trunc() funciona perfectamente.

Pero para:

double lotValue = ((_TickValue / _TickSize) * lot);

no lo hace, y por eso incluí también la función Round(number, digits); y solía hacer el truco, y decidí simplemente preguntarte si había una fórmula para combinar mi función Normalize_Double_ToString() en un código más simple y optimizado.

Y me respondiste algo muy muy diferente (asumo que es enteramente culpa mía por no explicarme bien)

Pero desde ayer Round() bloquea MT4, y sin Round no puedo contar correctamente los Dígitos Significativos en el lado de los decimales.

El problema parece ser el typecasting a long. Si lo quito de Round(double, int); MT4 ejecuta sin problema, pero entonces no puedo entender cómo un doble con 6 dígitos enteros, multiplicado por 10000, alcanza los límites de long.


Supongo que llegados a este punto mi pregunta es

¿Dónde está la salida?


De todas formas tendré que dejar pasar esto, volveré a ello en unas semanas.

 

Prueba esto:

string Normalize_Double_ToString(double n, int d)
{
   n = Round(n, d);
   d = MathMin(d, GetDigits(n);

   return DoubleToString(n, d);
}

sin embargo, no lo hará mucho mejor que los 3 métodos más cortos en el post anterior.

Nota,

Yo uso Round() de mi librería, no el incorrecto que posteaste antes, o en su lugar uso:

n = NormalizarDoble(n, d);

Pero, dudo de lo que has dicho que Round() tiene errores.
 
Cristian Dan Fechete #:

Parece que después de 4 mensajes no he sido capaz de hacerte entender mi problema, y me siento terriblemente decepcionado de mi fracaso.

Y el estilizador en este sitio es completamente bugged, por lo que es muy desperdiciador de tiempo para escribir correctamente un mensaje aquí

No puedo explicar por qué, pero debemos suponer que 1.000000000; tiene un decimal distinto de 0 en alguna parte, aunque gráficamente no fui capaz de mostrarlo.

Estoy seguro de que entiendo la causa de sus problemas en MT4.

La razón principal por la que no puede obtener los resultados esperados es un error con string(dbl) de MQL4 que aún no se ha solucionado en MT4.

Error en la función string() de MQL4. Conversión incorrecta de doble -> cadena.

Esto también afecta a cómo se muestran los dobles (a través de la conversión implícita a cadena) por Print(), Alert(), Comment(), FileWrite().

El error fue corregido en MT5, pero no en MT4. ver aquí: https: //www.mql5.com/en/forum/367839/page3#comment_27477157 y la solución aquí: https: //www.mql5.com/en/forum/367839/page5#comment_27613205

Mi recomendación:

si quieres profundizar o depurar tus dobles como string en MT4, entonces fuerza siempre el cast explícito a string mediante la función Repr() de math_utils.mqh

#include "math_utils.mqh"

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   double a = 1.0000000000000002;
   Print(a);         // 1.0 (error en la conversión implícita doble -> cadena)
   Print(Repr(a));   // 1.0000000000000002

   double b = 100.00000000000003;
   Print(b);         // 100.0 (error en la conversión implícita doble -> cadena)
   Print(Repr(b));   // 100.00000000000003
  }
MT5/mql5 reported and confirmed bugs. - Custom ZERO Level Showing ZERO level, bug in MML. String(MQ)
MT5/mql5 reported and confirmed bugs. - Custom ZERO Level Showing ZERO level, bug in MML. String(MQ)
  • 2022.02.01
  • Alain Verleyen
  • www.mql5.com
On indicators, mt5 can set automatically a level "0" depending of the buffer values. Custom indicator showing zero level, though not defined anywhere in the code. Wrong conversion of double -> string. Then test the same example in your browser js pad or any online javascript pad and check the difference