Почему sprintf в Perl неправильно округляет числа с плавающей точкой? - PullRequest
5 голосов
/ 30 октября 2009

Я искал соглашение о округлении, используемое встроенной функцией Perl sprintf .

Я думал, что он выполняет нормальное округление (например, ROUND_HALF_UP, как в Соглашение о режиме округления Java ), но дальнейшее копание доказало, что это неправильно:

> /usr/local/bin/perl5.10.1 -e 'print(sprintf("%.2f", shift @ARGV)."\n");' 0.335
0.34
> /usr/local/bin/perl5.10.1 -e 'print(sprintf("%.2f", shift @ARGV)."\n");' 1.335
1.33

Ответы [ 2 ]

16 голосов
/ 30 октября 2009

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

  DB<1> $a=0.335

  DB<5> print sprintf("%.19f",$a)
0.3350000000000000200
  DB<7> $b=1.335

  DB<8> print sprintf("%.19f",$b)
1.3349999999999999645
  DB<9> 

Поскольку 0,335 внутренне представляется немного большим, чем 0,335, оно округляется до 0,34, в то время как 1,335 немного меньше, чем 1,335, поэтому округляется до 1,33.

6 голосов
/ 30 октября 2009

Это функция чисел с плавающей точкой IEEE.

Для получения дополнительной информации в контексте Perl см. Perlfaq4 "Есть ли в Perl функция round ()" и, в частности, что она говорит о чередовании на полпути.

...