Почему я получаю разные результаты на Linux и OS / X - PullRequest
6 голосов
/ 12 апреля 2019

Я пытался выполнить очень простой printf тест:

printf "%.16f\n" 5.10

В Linux я получил такой вывод: 5.100000000000000000, что ожидается.

Но тот же тест на ОС/ X производит это: 5.0999999999999996

Почему printf производит другой вывод?

РЕДАКТИРОВАТЬ : Это не код C, printf также команда-линия, удобная для скриптов и тестов.

Эквивалентная программа на C ниже производит 5.100000000000000000:

#include <stdio.h>

int main() {
    printf("%.16f\n", 5.10);
    return 0;
}

EDIT 2 : сюжет утолщается ...чтобы сделать это более интересным для пользователей Linux, если я запускаю эту команду как nobody, я получаю то же поведение, что и в OS / X:

chqrlie$ printf "%.18f\n" 5.10
5.100000000000000000
chqrlie$ su nobody -c 'printf "%.18f\n" 5.10'
5.099999999999999645

Ответы [ 2 ]

8 голосов
/ 12 апреля 2019

И реализация GNU, и реализация MacOS (FreeBSD) printf являются разными программами.Оба стремятся быть совместимыми со стандартом POSIX.

POSIX оставляет представление чисел с плавающей запятой открытым для реализации printf.Их аргументация заключается в том, что все вычисления в оболочке в любом случае целочисленные.

Спецификации преобразования форматирования с плавающей точкой для printf () не требуются, поскольку вся арифметика в оболочке является целочисленной арифметикой.Утилита awk выполняет вычисления с плавающей точкой и предоставляет собственную функцию printf.Утилита bc может выполнять арифметику с плавающей точкой произвольной точности, но не предоставляет широких возможностей форматирования.(Эта утилита printf на самом деле не может использоваться для форматирования вывода bc; она не поддерживает произвольную точность.) Реализациям рекомендуется поддерживать преобразования с плавающей точкой в ​​качестве расширения.

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html


PS:

5.1

- это , а не число с плавающей запятой в bash.bash не поддерживает плавающие числа.

5.1 - это строка, интерпретируемая как printf в зависимости от локали (!)

theymann@theymann-laptop:~/src/sre/inventory-schema$ LANG=en_US.UTF8 printf "%.16f\n" 5.10
5.1000000000000000
theymann@theymann-laptop:~/src/sre/inventory-schema$ LANG=de_DE.UTF8 printf "%.16f\n" 5.10
bash: printf: 5.10: Ungültige Zahl. # << German: Bad Number
0,0000000000000000

Примечание. В Германии в качестведесятичный разделитель.


Разница в выводе между обычным пользователем и никто не должен оболочку, которая используется.некоторые оболочки, например busybox, имеют собственную реализацию printf.Кстати, я очень удивлен, что никто не может выполнять команды в вашей системе!

3 голосов
/ 12 апреля 2019

Это потому, что типы с плавающей запятой в большинстве случаев не могут представлять точные значения.Например, используя онлайн-инструмент IEE754, вы получили:

enter image description here

Так что 5.1 не может быть точно представлен в этом формате.

Тогдаprintf (или что-то еще) свободно форматировать / печатать любое значение, которое оно считает подходящим для пользователя.

...