Добрый день! Я сейчас изучаю язык C и столкнулся с вещами, которые на первый взгляд нелогичны.
Смотрите вопросы в коде с примерами:
#include <stdio.h>
#include <float.h>
int main(int argc, char *argv[])
{
double x = 999999999999999.99;
printf("%.2lf\n", x); //почему здесь вывод будет "1000000000000000.00" а не "999999999999999.99"?
x = DBL_MAX;
x = x - 1;
if(DBL_MAX == x) {printf("DBL_MAX == DBL_MAX - 1\n");} //почему программа отображает эту строчку?
x = 999999999999.12;
printf("%lf\n", x); //почему здесь выводится "999999999999.119995" а не "999999999999.12"?
}
Буду благодарен если кто-то из профессионалов даст ответы на данные вопросы.
Здравствуйте, esud, Вы писали:
E>Добрый день! Я сейчас изучаю язык C и столкнулся с вещами, которые на первый взгляд нелогичны.
Это особенность представления чисел с плавающей точкой.
Можно начать изучение с
Вики.
Здравствуйте, esud, Вы писали:
E>Добрый день! Я сейчас изучаю язык C и столкнулся с вещами, которые на первый взгляд нелогичны.
У этих вопросов вообще-то нет специфики C, есть специфика IEEE754 в частности, и операций с плавающей точкой в целом. Описанные проблемы будут в любом языке, который их использует.
E>Смотрите вопросы в коде с примерами:
E> double x = 999999999999999.99;
E> printf("%.2lf\n", x); //почему здесь вывод будет "1000000000000000.00" а не "999999999999999.99"?
Потому что представление в double имеет точность 53 двоичных цифры. Вы как раз перешли за этот порог, оно скомпилировало ближайшее значение, которое представимо в double.
E> x = DBL_MAX;
E> x = x — 1;
E> if(DBL_MAX == x) {printf("DBL_MAX == DBL_MAX — 1\n");} //почему программа отображает эту строчку?
Потому что предыдущее значение перед DBL_MAX, которое равно 2^1024-2^971, будет равно 2^1024-2*2^971, разница между ними равна 1.99584030953472e+292. Результат вычитания 1 даст результат, который будет округлён к ближайшему представимому значению, то есть обратно к DBL_MAX. (Знак ^ тут означает возведение в степень.)
Чтобы получить таки отличающееся значение, которое ближайшее к DBL_MAX и меньше его, вызовите
nextafter(DBL_MAX, -1).
E> x = 999999999999.12;
E> printf("%lf\n", x); //почему здесь выводится "999999999999.119995" а не "999999999999.12"?
Потому что на самом деле представленное число равно 999999999999.1199951171875 — это точный десятичный перевод того двоичного представления, которое лежит в x после такого присвоения.
Вывод с %lf выводит 6 десятичных разрядов послед занятой, округляя к последнему из них.
E>Буду благодарен если кто-то из профессионалов даст ответы на данные вопросы.
Вам надо внимательно сходить сюда и прочитать:
What Every Programmer Should Know About Floating-Point Arithmetic
What every computer scientist should know about floating-point (вариация предыдущего)
Машинные методы математических вычислений (хотя бы первые главы, где обсуждаются проблемы точности, ситуации катастрофической потери точности и т.п.) (книга есть в pdf в сети, сами найдёте, если что)
Все ответы на
вопрос, повторы которого задаются новичками каждые три дня, если не чаще.
За подробность — плюс (обычно новички ограничиваются вопросами типа "какого чёрта 0.1+0.2 != 0.3?"), но ещё есть много чему учиться.