Extraño comportamiento de la función pow

5 minutos de lectura

avatar de usuario
kroor singh

Mientras se ejecutan las siguientes líneas de código:

int i,a;    

for(i=0;i<=4;i++)  
{    
    a=pow(10,i);    
    printf("%d\t",a);    
}   

Me sorprendió ver la salida, resulta ser 1 10 99 1000 9999 en vez de 1 10 100 1000 10000.

¿Cuál puede ser la posible razón?

Nota

Si cree que es una inexactitud de punto flotante que en el bucle for anterior cuando i = 2los valores almacenados en la variable a es 99.

Pero si escribes en su lugar

a=pow(10,2);

ahora el valor de a resulta ser 100. ¿Cómo es eso posible?

  • ¿En qué plataforma y compilador observaste esto? lo intenté reproducirlo en ideonepero aparentemente su implementación de pow() devuelve resultados exactos para potencias enteras positivas de 10.

    – Ilmari Karonen

    09/08/2013 a las 21:35


  • Tenga en cuenta que un compilador de C razonable proporcionaría un fiel pow() función, con la cual este problema no ocurriría. blog.frama-c.com/index.php?post/2013/04/06/…

    – Pascal Cuoq

    09/08/2013 a las 21:39

  • @PascalCuoq: +1 por culpar a la mala implementación, pero para ser precisos, se trata de la implementación de la biblioteca, no del compilador.

    – R.. GitHub DEJA DE AYUDAR A ICE

    9 de agosto de 2013 a las 22:49

  • la pow() devuelve el doble que redondea el valor 100 como 99,9999. Y cuando imprime este valor como entero, muestra 99

    – Vighanesh Gursale

    15 de agosto de 2013 a las 6:50


  • @SurajJain Estás usando comentarios para hacer una nueva pregunta, lo cual es una idea terrible. Por favor, haga una nueva pregunta, que será respondida por quien tenga tiempo y sepa la respuesta.

    – Pascal Cuoq

    10/10/2016 a las 17:20

Ha establecido a ser un int. pow() genera un número de punto flotante, que en ALGUNOS casos puede ser solo un cabello menos de 100 o 10000 (como vemos aquí).

Luego metes eso en el número entero, que TRUNCA a un número entero. Entonces pierdes esa parte fraccionaria. Ups. Si realmente necesita un resultado entero, la ronda puede ser una mejor manera de realizar esa operación.

Tenga cuidado incluso allí, ya que para poderes lo suficientemente grandes, el error puede ser lo suficientemente grande como para causar una falla, brindándole algo que no espera. Recuerde que los números de punto flotante solo tienen cierta precisión.

  • Sí, lo importante es que convertir a int así trunca en lugar de redondear.

    – Hombre cuervo

    9 de agosto de 2013 a las 21:29

  • entonces, ¿cómo es posible que la misma función produzca una salida 100 cuando simplemente escribes a=pow(10,2); (en lugar de 99 que se produce en el ciclo for para i=2)

    – Kroor Singh

    10 de agosto de 2013 a las 14:46


  • @MayankJha No lo es requerido que hay ser un error. Solo es posible. Para ciertos valores.

    usuario529758

    13 de agosto de 2013 a las 20:03

  • @MayankJha: porque cuando se trata de números de punto flotante, no se requiere que los literales constantes tengan la misma precisión de redondeo que las variables con el mismo valor. Entonces, el compilador tiene la libertad de evaluar las expresiones constantes en tiempo de compilación con más precisión y obtener un resultado ligeramente diferente, que termina siendo muy diferente con el truncado.

    – Chris Dodd

    13 de agosto de 2013 a las 20:09


  • @ChrisDodd Señor, la persona preguntó eso en cuestión y nadie lo respondió con esta optimización del compilador, ¿puede usted?

    – Suraj Jain

    12 de febrero de 2017 a las 11:52

La función pow() devuelve un double. Lo estás asignando a la variable ade tipo int. Hacer eso no “redondea” el valor de coma flotante, lo trunca. Asi que pow() está devolviendo algo así como 99.99999… por 10^2, y luego solo estás tirando la parte .9999… mejor decir a = round(pow(10, i)).

  • o (int)(pow(10,i)+0.5) (equivalente aproximado de redondo)

    – tecnosaurio

    09/08/2013 a las 21:33

  • OP pow() tiene sorprendentes debilidades.

    – chux – Reincorporar a Monica

    9 de agosto de 2013 a las 22:17

  • Pero cuando asigno variable a de tipo float para pow() . Vuelve 100.000000 en vez de 99.9999999 porque ?

    – Suraj Jain

    27 de julio de 2016 a las 2:50

  • @chux Pero cuando asigno la variable a de tipo float a pow() . Devuelve 100.000000 en lugar de 99.9999999 ¿por qué?

    – Suraj Jain

    24/08/2016 a las 17:30

  • @Suraj Jain C no especifica la calidad de pow() resultados. Las implementaciones de alta calidad (como la suya) devolverían 100.0 en pow(100,2). Los de menor calidad (como los OP) pueden devolver algunos ULP fuera de las expectativas como 99.999999999999985…, detalle: el código de operación no implica float. Los valores `flotantes típicos antes/después de 100.0f son 99.9999924… y 100.0000076… en lugar de 99.9999999

    – chux – Reincorporar a Monica

    24 de agosto de 2016 a las 18:22


esto tiene que ver con inexactitud de punto flotante. Aunque estés de paso ints se están convirtiendo implícitamente a un tipo de coma flotante ya que el pow La función solo se define para parámetros de punto flotante.

  • El artículo al que vincula describe la representación de números de punto flotante y algunos de los principios detrás de ellos, pero no es relevante aquí porque tanto el argumento como el resultado de pow(10, 2) son exactamente representables como double. En cambio, el OP está usando una implementación inferior de pow()un tema no abordado en el artículo.

    – Pascal Cuoq

    09/08/2013 a las 21:47


avatar de usuario
JackCColeman

Matemáticamente, la potencia entera de un número entero es un número entero.

en una buena calidad pow() rutina este cálculo específico NO debería producir ningún error de redondeo. Ejecuté su código en Eclipse/Microsoft C y obtuve el siguiente resultado:

1   10  100 1000    10000   

Esta prueba NO indica si Microsoft está usando flotantes y redondeando o si están detectando el tipo de sus números y eligiendo el método apropiado.

Entonces, ejecuté el siguiente código:

#include <stdio.h>
#include <math.h>
main ()
{
    double i,a;

    for(i=0.0; i <= 4.0 ;i++)
    {
        a=pow(10,i);
        printf("%lf\t",a);
    }
}

Y obtuve el siguiente resultado:

1.000000    10.000000   100.000000  1000.000000 10000.000000    

Nadie explicó cómo Realmente hacerlo correctamente – en lugar de pow función, solo tiene una variable que rastrea la potencia actual:

int i, a, power;    

for (i = 0, a = 1; i <= 4; i++, a *= 10) {    
    printf("%d\t",a);    
}

Se garantiza que esta multiplicación continua por diez le dará la respuesta correcta, y bastante bien (y mucho mejor que pow, incluso si estuviera dando los resultados correctos) para tareas como convertir cadenas decimales en números enteros.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad