Блок if-else и неожиданные результаты с типом данных float.[Отредактировано еще с одним вопросом] - PullRequest
1 голос
/ 02 сентября 2010

Я скомпилировал следующую программу с gcc 4.4.1, и я получил неожиданный вывод (ну, неожиданно для меня)

#include<stdio.h>

int main()
{
        float x=0.3, y=0.7;

        if(x==0.3)
        {
                if(y==0.7)
                        printf("Y\n\n");
                else
                        printf("X\n\n");
        }
        else
                printf("NONE\n\n");
}


Output: NONE

#include<stdio.h>

int main()
{
        float x=0.3, y=0.7;

        if(x<0.3)
        {
                if(y==0.7)
                        printf("Y\n\n");
                else
                        printf("X\n\n");
        }
        else
                printf("NONE\n\n");
}

Output: NONE

#include<stdio.h>

int main()
{
        float x=0.3, y=0.7;

        if(x>0.3)
        {
                if(y>0.7)
                        printf("Y\n\n");
                else
                        printf("X\n\n");
        }
        else
                printf("NONE\n\n");
}

    Output:X

Итак, это ясновидно, что сохраненное значение в «x» больше 0,3, а сохраненное значение в «y» меньше 0,7

Почему это происходит?Это свойство типа данных float или операторы if-else интерпретируют float по-другому?

Спасибо.


Редактировать: Хорошо, я обдумал это, и я получаюнемного смущен сейчас.Пожалуйста, скажите, правильно ли я понимаю эту проблему.

float x=0.3;

Это хранит x=0.30000001192092895508 в памяти.Очевидно, что это больше, чем 0.3 (это правильно?)

Теперь, double x=0.3 приводит к x=0.29999999999999998890, и это меньше, чем 0,3 (Это тоже правильно?)

Основной вопрос: так что если я использую store 0.3 в float x, то следующее утверждение if(x>0.3) приводит к тому, что x=0.30000001192092895508 неявно приводится к типу double, а 0.3 также является double вместо float.Следовательно, 0.3=0.29999999999999998890 и внутренняя операция if((double) 0.30000001192092895508 > (double) 0.29999999999999998890).Это правильно?

Ответы [ 2 ]

7 голосов
/ 02 сентября 2010

Вы используете float для хранения, но вы выполняете сравнения с литералами типа double.

Значения x и y не совсем 0,3 и 0,7, так как эти числа не представимы в двоичной с плавающей запятой. Бывает, что самые близкие значения float до 0,3 больше, чем самые близкие значения double до 0,3, а самые близкие значения float до 0,7 меньше, чем самые близкие значения double до 0,7 ... отсюда результаты вашего сравнения.

Если предположить, что представления такие же, как в C # (где у меня есть некоторые инструменты, которые могут помочь), используются следующие значения:

0.3 as float = 0.300000011920928955078125
0.3 as double = 0.299999999999999988897769753748434595763683319091796875
0.7 as float = 0.699999988079071044921875
0.7 as double = 0.6999999999999999555910790149937383830547332763671875

Так что это объясняет, почему это происходит ... но не объясняет, как обойти эту проблему, конечно же, независимо от того, что ваш код пытается сделать. Если вы можете дать больше контекста для большей проблемы, мы можем помочь больше.

3 голосов
/ 02 сентября 2010

Компьютеры не могут точно хранить числа с плавающей запятой.Точно так же, как 1/7 не может быть представлено конечным числом десятичных цифр, множество чисел не может быть представлено точно в двоичном виде.3/10 такое число.Когда вы пишете 0.3, ваша программа на самом деле сохраняет 0.30000001192092895508, поскольку это лучшее, что она может сделать с 32-битными доступными ей переменными float.

И так получается, что это значение также отличается от значения double 0.3, поскольку компьютер может хранить больше цифр в 64-разрядном double.Когда вы пишете if (x == 0.3), ваше значение фактически увеличивается до double, поскольку константы с плавающей точкой имеют значение double s, если явно не указано иное.Это эквивалентно записи if ((double) x == 0.3).

jkugelman$ cat float.c
#include <stdio.h>

int main() {
    printf("%.20f\n", (float)  0.3);  // Can also be written "0.3f".
    printf("%.20f\n", (double) 0.3);  // Cast is redundant, actually.
    return 0;
}

jkugelman$ gcc -Wall -o float float.c

jkugelman$ ./float
0.30000001192092895508
0.29999999999999998890

Обратите внимание, что значение 0.2999... содержит больше 9, чем 0.3000....Значение двойной точности ближе к 0.3 благодаря дополнительным битам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...