Информация об изменениях

Сообщение Re: Вопросы связанные с типом "double" от 01.05.2018 7:07

Изменено 01.05.2018 7:10 netch80

Re: Вопросы связанные с типом "double"
Здравствуйте, 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?"), но ещё есть много чему учиться.
  • Re: Вопросы связанные с типом "double"
    Здравствуйте, 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?"), но ещё есть много чему учиться.