Подтвердить что ты не робот

Поведение округления округления для удвоений

Может кто-нибудь объяснить это поведение? Мне хорошо известно представление чисел с плавающей точкой на уровне машины. Это похоже на printf и его форматы. Оба числа представлены точно с помощью нотации с плавающей запятой (проверка: умножение на 64 дает целое число).

#include <stdio.h>
#include <iostream>
using namespace std;

int main() {
  double x1=108.765625;
  printf("%34.30f\n", x1);
  printf("%9.5f\n", x1);
  printf("%34.30f\n", x1*64);

  double x2=108.046875;
  printf("%34.30lf\n", x2);
  printf("%9.5f\n", x2);
  printf("%34.30f\n", x2*64);
}

Вывод:

> 108.765625000000000000000000000000
> 108.76562
> 6961.000000000000000000000000000000
> 108.046875000000000000000000000000
> 108.04688
> 6915.000000000000000000000000000000

Обратите внимание: первое число округляется, а второе округляется.

4b9b3361

Ответ 1

Это "раунд от половины к четному" или "округление банкира". Последняя цифра округленного представления выбрана равной, даже если число находится на полпути между ними.

http://linuxgazette.net/144/misc/lg/a_question_of_rounding_in_issue_143.html:
"Для библиотеки GNU C правило округления, используемое printf(), - это" округление банкиров "или" округление до четного ". Это более корректно, чем некоторые другие библиотеки C, поскольку спецификация C99 говорит о том, что преобразование в десятичное значение должно использовать выбранный круглый режим IEEE (округление байкеров по умолчанию).

Ответ 2

Выход %9.5f дает число с 5 цифрами после десятичной точки, которая является ближайшим к исходному номеру.