¿Cómo se comparan doubles en C++?

Si tenemos dos valores tales como a = 0.999999... y b = 1.0, es decir que son representaciones decimales del mismo número real 1, no obstante la expresión x == y será evaluada como false... el siguiente código funciona, pero si uso un bucle para imprimir por pantalla la altura del objeto en función del tiempo t entonces la altura h acaba siendo ligeramente negativa en lugar de devolverme cero...

//
// describir la trayectoria de un objeto que cae desde una  
// altura de 100 metros hasta que se detiene en el suelo
//

#include <iostream>
#include <cmath>

constexpr double altura_sub0{ 100.0 };
constexpr double g{ 9.81 };

int main()
{
    double t_iter{ 0.0 };
    double t{ sqrt(altura_sub0 / (g / 2)) };
    double h{ altura_sub0 };
    h = altura_sub0 - g*t*t / 2;
    if (h == 0.0)
        std::cout << "resultado correcto de h = 0 en tiempo "
        << t << " segundos." << std::endl;
    else
        std::cout << "fallo!, tras " << t << " segundos el objeto"
        "se encuentra en h = " << h << std::endl;
 }
1
задан 23.12.2016, 00:34
2 ответа

В общем сравнивать две переменные double он не делается с ==, ввиду внутреннего представления этой реальной стоимости (mantisa, выразитель).

Самое общее состоит в том, чтобы оценивать, если различие между этой двумя стоимостью меньше, чем один EPSILON что заблаговременно определяется (согласно точности, которой требуют), и если различие меньше, говорят, что числа равны.

Функция тип

bool isEqual(double d1, double d2, double epsilon = 0.00000000001)
{
    return fabs(d1 - d2) < epsilon;
}

Пример

#include <iostream>
#include <stdio.h>
#include <cmath>


bool isEqual(double d1, double d2, double epsilon = 0.000000001)
{
    return fabs(d1 - d2) < epsilon;
}

int main()
{
    double primero=.33333;
    double segundo=1.0/3.0;

    printf ("primero: %.20f\n", primero);
    printf ("segundo: %.20f\n", segundo);

    std::cout << "isEqual: " << (isEqual(primero, segundo)) << "\n"; //Epsilon por defecto
    std::cout << "isEqual: " << (isEqual(primero, segundo, 0.0001)) << "\n"; 

 }

Результат

primero: 0.33333000000000001517
segundo: 0.33333333333333331483
isEqual: 0
isEqual: 1
2
ответ дан 24.11.2019, 11:54
  • 1
    nú морские окуни в плавающей запятой не должны сравниваться между sí используя оператор comparació n, потому что Ваш representació n она не является точной и está подчини в в десятичные не значительные, что могут " bailar" и делать, что comparació n не удайтесь. Из-за многого, что у них был mantisa и выразитель Ваш representació n está нормализованная, потом тот же nú морской окунь representará точно равный в двух различных переменных... проблема, - когда мы реализуем операции на вышеупомянутой стоимости. Выражение другой формы: это может не удаваться: (1e10+1.0-1.0==1e10) в то время как это не fallará 1e10==1e10 – eferion 16.01.2017, 18:50

Ты должен избегать сравнивать числа в плавающей запятой посредством равенства, у каждого из чисел может быть отличная точность, как Ваш тип или Ваша стоимость может не быть exáctamente перепредставительно бинарным способом вызывая ошибки округления.

В пользу этого мотива ты они должен сравнивать из-за почти равенство, такая функция ты могла бы помогать:

#include <cstdint> 

bool casi_iguales(float izquierda, float derecha)
{
     return fabs(izquierda – derecha) <= FLT_EPSILON;
}

bool casi_iguales(double izquierda, double derecha)
{
     return fabs(izquierda – derecha) <= DBL_EPSILON;
}

Стоимость FLT_EPSILON и DBL_EPSILON они принадлежат заголовку <cstdint> и это - различие между стоимостью 1 и следующая перепредставительная стоимость из-за float и double соответственно; в других словах, это приблизительно самая меньшая перепредставительная стоимость из-за каждого из типов, так что если различие между izquierda и derecha он меньший или равен этой стоимости состоит в том, что обе стоимость почти равна.

4
ответ дан 24.11.2019, 11:54