C - Суммирование с двойной точностью - PullRequest
0 голосов
/ 13 октября 2011

У меня проблема с точностью двойной формат .


Пример примера:

double K=0, L=0, M=0;
scanf("%lf %lf %lf", &K, &L, &M);
if((K+L) <= M) printf("Incorrect input");
else printf("Right, K=%f, L=%f, M=%f", K, L, M);

Мой тестовый ввод:

K = 0,1, L = 0,2, M = 0,3 -> Условие, но переходит к 'else' заявлению.


Как я могу исправить эту разницу? Есть ли другой способ суммирования?

Ответы [ 3 ]

5 голосов
/ 13 октября 2011

В мире двоичного формата IEEE 754 двойной точности с плавающей запятой (те, которые используются в Intel и других процессорах) 0.1 + 0.2 == 0.30000000000000004 :-) И 0.30000000000000004 != 0.3 (и обратите внимание, что в изумительном мире double с, 0,1, 0,2 и 0,3 не существуют как «точные» величины. Есть несколько двойных чисел, которые очень близки к ним, но если вы напечатаете их с полной точностью, они не будут 0,1, 0,2 и 0,3)

Чтобы немного посмеяться, попробуйте это: http://pages.cs.wisc.edu/~rkennedy/exact-float

Вставьте десятичное число и посмотрите на второй и третий ряд, оно показывает, как число действительно представлено в памяти. Это для Delphi, но Double и Single одинаковы для Delphi и, вероятно, для всех компиляторов C для процессоров Intel (они называются double и float в C)

И если вы хотите попробовать сами, посмотрите на это http://ideone.com/WEL7h

#include <stdio.h>

int main()
{
    double d1 = (0.1 + 0.2);
    double d2 = 0.3;

    printf("%.20e\n%.20e", d1, d2);

    return 0;
}

выход:
3.00000000000000044409e-01
2.99999999999999988898e-01

(учтите, что вывод зависит от компилятора. В зависимости от параметров, 0.1 + 0.2 может быть скомпилирован и округлен до 0,3)

1 голос
/ 13 октября 2011

В отличие от целочисленных значений, значения с плавающей точкой хранятся не совсем так, как вы присваиваете им значения. Давайте рассмотрим следующий код:

int i = 1; // this is and always will be 1
float j = 0.03 // this gets stored at least on my machine as something like 0.029999999

Почему это так? Ну, сколько чисел с плавающей запятой существует в интервале от 0,1 до 0,2? Бесконечное число! Таким образом, есть значения, которые будут сохранены, как вы и предполагали, но чертовски много значений, которые будут сохранены с небольшой ошибкой.

Это причина, по которой сравнение значений с плавающей точкой на равенство не является хорошей идеей. Попробуйте что-то вроде этого:

float a = 0.3f;
float b = 0.301f;
float threshold = 1e-6;

if( abs(a-b) < threshold )
  return true;
else
  return false;
0 голосов
/ 13 октября 2011

Между любыми двумя действительными числами существует бесконечно много действительных чисел.Если бы мы могли представлять каждого из них, нам была бы нужна бесконечная память.Поскольку у нас только ограниченная память, числа с плавающей точкой должны храниться только с конечной точностью.Вплоть до этой конечной точности, может быть неверно, что 0,1 + 0,2 <= 0,3. </p>

Теперь вы действительно должны прочитать то, что находится на другом конце превосходной ссылки, предоставленной Полом Р.

...