Velocidad de ejecución de las funciones ceil(),round(),floor() - página 4

 
Alexey Navoykov:

Así que DBL_EPSILON tiene 16 decimales:2,2204460492503131e-016

Y en tu caso sí que lo consigues, ya que la diferencia es sólo de 1e-16, que es 2 veces menos que epsilon.


Funciona con 0,9999999999999997, pero con 0,9999999999999998 ya no funciona.

 
Nikolai Semko:

Funciona con 0,9999999999999997, pero con 0,9999999999999998 ya no funciona.


Aquí hay otro truco:

Y=(int)(x+1-2*DBL_EPSILON);
Print(Y);                             // 3
Y=(int)(x+1-DBL_EPSILON-DBL_EPSILON);
Print(Y);                             // 4
 

El número 2,2204460492502503131e-016 en notación decimal significa la resolución del formato doble (https://msdn.microsoft.com/ru-ru/library/6bs3y5ya(v=vs.100).aspx), esto

El menor número positivo x, tal que x + 1,0 no es igual a 1,0.

- El menor número positivo tal que al sumarle 1,0 cambia el valor del número. En otras palabras, es el error relativo de la representación de un número. Es decir, para 16 este límite contendrá tantos nueves decimales, y para 64 al final será 4 veces más que 1, para 8 la mitad. Así que tendremos que calcular esta precisión para acelerar el redondeo con la mayor precisión posible. Es poco probable que estos cálculos sean más rápidos que el rendimiento de las funciones de redondeo normales. Como MQL no permite trabajar directamente con direcciones de números, no podremos tomar bits de un orden en el número, por lo que tendremos que inventar el análogo de la función log en base 2. Es poco probable que funcione rápidamente.

Пределы констант с плавающей запятой
Пределы констант с плавающей запятой
  • msdn.microsoft.com
В следующей таблице представлены ограничения на значения констант с плавающей запятой. Эти ограничения также заданы в стандартном файле заголовка FLOAT.H. Ограничения на константы с плавающей запятой КонстантаЗначениеЗначение Количество цифр q, при котором число с плавающей запятой с q десятичными цифрами можно округлить в представление с...
 
Nikolai Semko:

Aquí hay otro truco:

Resulta que cualquier operación matemática introduce un error adicional, que puede ser mayor o menor. Por lo tanto, en general, como señaló Vladimir, es necesario normalizar el resultado.

 

ceil(), floor() es poco probable que se reproduzcan porque el modo de redondeo de la FPU no se puede controlar desde μl. Lo único que probablemente funcione más o menos adecuadamente es round() y no es exacto según la norma. Por cierto, este es el aspecto aproximado de C-shaped round():

double round(double x)
{
    fenv_t save_env;
    feholdexcept(&save_env);
    double result = rint(x);
    if (fetestexcept(FE_INEXACT)) {
        fesetround(FE_TOWARDZERO);
        result = rint(copysign(0.5 + fabs(x), x));
    }
    feupdateenv(&save_env);
    return result;
}
 
Para entender lo que se quiere redondear aquí, hay que saber exactamente cómo y qué se pierde al convertir el formato DOBLE al formato INT. en este caso, sólo se obtiene la parte entera, que queda después del redondeo. como consecuencia, cualquier número con cualquier número de decimales y cualquier dígito después del punto decimal se eliminará y sólo quedará la parte entera.
ejemplo:
2.1758716871 -> (int)2.1758716871 = 2
2.0000000001 -> (int)2.0000000001 = 2
2.9999999999 -> (int)2.9999999999 = 2
esto se llama pérdida de precisión cuando se reformula un número.
como consecuencia
MathFloor(x)  =  (int)(x)
MathCeil(x)   =  (int)(x)+1;
MathRound(x)  =  (int)(x+0.5)

Sinceramente.
 
Andrey Kisselyov:
Para entender lo que se quiere redondear aquí, hay que saber exactamente cómo y qué se pierde al convertir el formato DOBLE al formato INT. en este caso, sólo se obtiene la parte entera, que queda después del truncamiento. en consecuencia, cualquier número con cualquier número de decimales y cualquier dígito después de la coma se eliminará y sólo quedará la parte entera.
ejemplo:Se denomina pérdida de precisión cuando se reformula un número.
como consecuencia

Sinceramente.

¿Por qué es tan complicado?

MathRound(x)  - >  (int)(x)+(int)(2.*(x-(int)(x)));

¿Cómo es esto mejor que el más simple?

MathRound(x)  ->  (int)(x+0.5);
 
Alexey Navoykov:

Resulta que cualquier operación matemática introduce un error adicional, que puede ser positivo o negativo. Por lo tanto, en el caso general, como señala Vladimir, es necesario normalizar el resultado.


pavlick_:

ceil(), floor() es poco probable que se repliquen, ya que el modo de redondeo de la FPU no se puede controlar desde μl. Lo único que probablemente funcione más o menos adecuadamente es round() y no es exacto según la norma. Por cierto, este es aproximadamente el aspecto de C-shaped round():


Por supuesto, tienes razón. Pero lo repetiré. Para el 99,9% de las tareas es absolutamente correcto sustituir las funciones de redondeo por una variante alternativa más rápida que utilice la conversión de tipos fraccionarios a (int) o (long). Un programador experimentado sólo tiene que ser consciente de este hecho y aplicarlo cuando sea necesario.

Для положительных x:
y=floor(x); -> y=(int)x;
y=ceil(x);  -> y=(int)(x+0.9999999999999997);
y=round(x); -> y=(int)(x+0.5);
 
Nikolai Semko:

¿Por qué es tan complicado?

¿Cómo es esto mejor que el más simple?

puedes probarlo así.

Nikolai Semko:
Un programador experimentado sólo tiene que ser consciente de este hecho y aplicarlo cuando sea conveniente.

No es que deba, debe saberlo.

Con respeto.

P.D. Su fórmula no es correcta para todo el conjunto de valores.
y=ceil(x);  -> y=(int)(x+0.9999999999999997);
ver la mía, he actualizado la ronda a una fórmula corta, ahora la lista es completa y totalmente funcional, utilizarlo.
 
Andrey Kisselyov:


P.D. su fórmula no es verdadera para todo el conjunto de valores.

ver la mía, he actualizado la ronda a una fórmula corta, ahora la lista es completa y totalmente funcional, utilizarlo.

ver arriba

cuando x = 3 (cualquier número entero), hay un atasco :))