Проблема с числом с плавающей запятой в C и Python - PullRequest
1 голос
/ 16 июня 2020

Я задавал несколько вопросов в C, и меня попросили предоставить результат этого вопроса:

#include <stdio.h>

int main()
{
    float a =0.7;
    if(a<0.7)
    {
        printf("Yes");
    }
    else{
        printf("No");
    }
}

Просто взглянув на проблему, я подумал, что ответ будет НЕТ но после запуска я обнаружил, что это было ДА Я поискал в Интернете информацию о float и нашел 0.30000000000000004.com

Просто из любопытства я запустил тот же код в python:

x = float(0.7)
if x < 0.7 : 
    print("YES")
else : 
    print("NO")

Здесь вывод NO

Я запутался!
Возможно, я что-то упускаю
Помогите, пожалуйста, с этой проблемой.

Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 16 июня 2020
float a = 0.7;
if(a<0.7)

Первая строка выше берет double 0.7 и помещает его в float, который почти наверняка имеет меньшую точность (так что вы можете потерять информацию).

Вторая строка обновляет float a до double (потому что вы сравниваете его с double 0.7, и это одна из вещей, которые C делает для вас), но в этот момент уже слишком поздно, информация уже исчезла.

Вы можете увидеть этот эффект с:

#include <stdio.h>

int main(void) {
    float a = 0.7;
    float b = 0.7f;
    double c = 0.7;
    printf("a %.50g\nb %.50g\nc %.50g\n", a, b, c);
    return 0;
}

, который генерирует что-то вроде:

a 0.699999988079071044921875
b 0.699999988079071044921875
c 0.69999999999999995559107901499373838305473327636719

Очевидно, переменная double c имеет примерно вдвое большую точность (вот почему их часто называют одинарной и двойной точностью), чем обе:

  • double 0.7 втиснуты в переменную float a; и
  • переменная float b, в которой хранится float 0.7.

Ни один из них не совпадает с 0.7 из-за способа плавающего числа точек работают, но double ближе к желаемому значению, следовательно, не равно float.

Это как налить полное четырехлитровое ведро воды в трехлитровое, а затем снова. Литр, который вы потеряли при переполнении меньшего ведра, волшебным образом не появляется снова: -)

Если вы измените тип своего a на double или используете float литералы, например 0.7f, вы обнаружите, что все работает лучше, чем вы ожидаете, поскольку в этом случае нет потери точности.


Причина, по которой вы не видите такого же эффекта в Python, заключается в том, что есть один базовый тип для этих значений с плавающей запятой:

>>> x = float(.7)
>>> type(x)
<class 'float'>
>>> type(.7)
<class 'float'>

Из Python документов:

Есть три различных типа numeri c : целые числа, числа с плавающей запятой и комплексные числа. Кроме того, логические значения - это подтип целых чисел. Целые числа имеют неограниченную точность. Числа с плавающей запятой обычно реализуются с использованием double in C.

Следовательно, в этом случае нет потери точности.

использование double, похоже, подтверждается (слегка переформатировано):

>>> import sys
>>> print(sys.float_info)
sys.float_info(
    max=1.7976931348623157e+308,
    max_exp=1024,
    max_10_exp=308,
    min=2.2250738585072014e-308,
    min_exp=-1021,
    min_10_exp=-307,
    dig=15,
    mant_dig=53,
    epsilon=2.220446049250313e-16,
    radix=2,
    rounds=1
)

Показатели степени и минимальные / максимальные значения идентичны значениям IEEE754 двойной точности .

0 голосов
/ 16 июня 2020

В a<0.7 константа 0.7 - это double, тогда a, который является float, перед сравнением повышается до double.
Ничто не гарантирует, что эти две константы (как float и как double) совпадают.

Как float дробная часть 0.7 равна 00111111001100110011001100110011; как double дробная часть 0.7 равна 0110011001100110011001100110011001100110011001100110.
Значение, преобразованное из float, будет иметь мантиссу, заполненную 0 s при повышении до double.
Сравнение этих двух последовательностей бит показывает, что константа double больше константы float (второй бит уже отличается), что приводит к отображению "Yes".

С другой стороны, в python только представление double существует для чисел с плавающей запятой; таким образом, нет разницы между тем, что хранится в a, и константой 0.7 сравнения, что приводит к отображению "No".

...