Comportamiento anormal de puntos flotantes y valores dobles

Float es un número de coma flotante de precisión simple IEEE 754 de 32 bits de 1 bit para el signo (8 bits para el exponente y 23* para el valor), es decir, float tiene 7 dígitos decimales de precisión.

Double es un número de punto flotante de precisión doble IEEE 754 de 64 bits (1 bit para el signo, 11 bits para el exponente y 52* bits para el valor), es decir, double tiene 15 dígitos decimales de precisión.

Este artículo se enfoca en discutir el comportamiento anormal de los valores dobles y de punto flotante.

Programa 1:

C

// C program to illustrate the abnormal
// behaviours of floating point value
#include <stdio.h>
  
// Driver Code
int main()
{
    float f = 0.2;
    if (f == 0.2)
        printf("it's geek time");
    else if (f < 0.2)
        printf("it's party time");
    else
        printf("it's movie time");
    return 0;
}

C++

// C++ program to illustrate the abnormal
// behaviours of floating point value
#include <iostream>
using namespace std;
  
// Driver Code
int main()
{
    float f = 0.2;
    if (f == 0.2)
        cout << "it's geek time";
    else if (f < 0.2)
        cout << "it's party time";
    else
        cout << "it's movie time";
    return 0;
}
Producción:

it's movie time

Explicación: En el programa anterior, la salida es «es hora de la película» en lugar de «es hora de geek». Así que aquí está la explicación de que como f es un valor de punto flotante y ‘0.2’ es un valor doble, debido a la diferencia de precisión de ambos tipos de datos, se puede ver este comportamiento anormal. En la declaración, si (f == 0.2), f se compara con 0.2, por lo tanto, internamente está escrito así:

if((double)(float)(0.2) == (0.2))

Como 0.2 es la primera conversión a flotante mientras se declara y asigna en la línea anterior (debido a lo cual la precisión disminuye y se redondea después de que se produce algún valor y se pierde algo de información/precisión) y después de eso, se vuelve a convertir en el doble en la instrucción if, pero el valor perdido no se puede recuperar. Por lo tanto, este comportamiento se puede ver.

Para una comprensión más clara, tomemos un ejemplo (analogía) del sistema numérico de base 10.

Tomemos 10/3 y representémoslo con 5 cifras significativas: 3.3333 o 3.3334 (en el caso de redondeo). Ese es el “flotador” f. Ahora convierta el valor de f en un valor con 8 cifras significativas (f en «doble»): 3,3333000 o 3,3334000 (en el caso de redondeo). Eso no es igual a 3.3333333 (El valor de 10/3 directamente como doble). 

Formas de evitar el comportamiento anormal :

Reemplace float f = 0.2 con double f = 0.2 o long double f = 0.2 mientras declara/inicializa la variable:

A continuación se muestra el programa C/C++ para ilustrar la idea anterior:

C

// C program to illustrate the above idea
#include <stdio.h>
  
// Driver Code
int main()
{
    // Declare as double or long double
    // or long double f = 0.2;
    double f = 0.2;
    if (f == 0.2)
        printf("it's geek time");
    else if (f < 0.2)
        printf("it's party time");
    else
        printf("it's movie time");
  
    return 0;
}

C++

// C program to illustrate the above idea
#include <iostream>
using namespace std;
  
// Driver Code
int main()
{
    // Declare as double or long double
    // or long double f = 0.2;
    double f = 0.2;
    if (f == 0.2)
        cout << "it's geek time";
    else if (f < 0.2)
        cout << "it's party time";
    else
        cout << "it's movie time";
    return 0;
}
Producción:

it's geek time

Typecast 0.2 a un flotador mientras compara dentro de la declaración if :

A continuación se muestra el programa C/C++ para ilustrar la idea anterior:

C

// C program to illustrate the above idea
#include <stdio.h>
  
// Driver Code
int main()
{
    float f = 0.2;
  
    // Typecast 0.2 as a float
    if (f == (float)0.2)
        printf("it's geek time");
    else if (f < (float)0.2)
        printf("it's party time");
    else
        printf("it's movie time");
    return 0;
}

C++

// C++ program to illustrate the above idea
#include <iostream>
using namespace std;
  
// Driver Code
int main()
{
    float f = 0.2;
  
    // Typecast 0.2 as a float
    if (f == (float)0.2)
        cout << "it's geek time";
    else if (f < 0.2)
        cout << "it's party time";
    else
        cout << "it's movie time";
    return 0;
}
Producción:

it's geek time

Escribe 0.2 como un valor de coma flotante:

 A continuación se muestra el programa C/C++ para ilustrar la idea anterior:

C

// C program to illustrate the above idea
#include <stdio.h>
  
// Driver Code
int main()
{
    float f = 0.2;
  
    // Replace 0.2 with 0.2f
    if (f == 0.2f)
        printf("it's geek time");
    else if (f < 0.2f)
        printf("it's party time");
    else
        printf("it's movie time");
    return 0;
}

C++

// C++ program to illustrate the above idea
#include <iostream>
using namespace std;
  
// Driver Code
int main()
{
    float f = 0.2;
  
    // Replace 0.2 with 0.2f
    if (f == 0.2f)
        cout << "it's geek time";
    else if (f < 0.2)
        cout << "it's party time";
    else
        cout << "it's movie time";
    return 0;
}
Producción:

it's geek time

Al verificar si la diferencia entre ambos valores es muy pequeña (1e-9) al declarar una variable de diferencia aceptable:

A continuación se muestra el programa C/C++ para ilustrar la idea anterior:

C

// C program to illustrate the above idea
#include <stdio.h>
#include <stdlib.h>
  
// Driver Code
int main()
{
    float f = 0.2;
  
    // Declare a variable with very small value
    // float acceptableDifference = 1e-9;
    float acceptableDifference = 0.00000001;
  
    // Check if the diff of both values is
    // less than this variable
    if (abs(f - 0.2) < acceptableDifference)
        printf("it's geek time");
    else if (f < 0.2)
        printf("it's party time");
    else
        printf("it's movie time");
  
    return 0;
}

C++

// C++ program to illustrate the above idea
#include <bits/stdc++.h>
using namespace std;
  
// Driver Code
int main()
{
    float f = 0.2;
  
    // Declare a variable with very small value
    // float acceptableDifference = 1e-9;
    float acceptableDifference = 0.00000001;
  
    // Check if the diff of both values is
    // less than this variable
    if (abs(f - 0.2) < acceptableDifference)
        cout << "it's geek time";
    else if (f < 0.2)
        cout << "it's party time";
    else
        cout << "it's movie time";
    return 0;
}
Producción:

it's geek time

Nota: Se prefiere este último método cuando no es necesario cambiar el tipo de datos de ninguna variable en ninguna parte del programa; de lo contrario, también se puede seguir cualquiera de los métodos enumerados anteriormente, ya que son fáciles, breves y menos complicados. Sea extremadamente cauteloso y cuidadoso al comparar números de punto flotante en las declaraciones if.

Publicación traducida automáticamente

Artículo escrito por anuragayu y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *