Двоичный файл плавающая точка математика похож на это. На большинстве языков программирования это основано стандарт IEEE 754 . JavaScript использует 64-разрядное представление с плавающей точкой, которое совпадает с Java double
. Затруднение проблемы - то, что числа представлены в этом формате в целом времена числа питание два; рациональные числа (такой как 0.1
, который является 1/10
), чей знаменатель не является питанием два, не могут быть точно представлены.
Для 0.1
в стандарте binary64
формат, представление может быть записано точно как [1 138]
0.1000000000000000055511151231257827021181583404541015625
в десятичном числе, или 0x1.999999999999ap-4
в [1 127] нотация . C99 hexfloat Напротив, рациональное число 0.1
, которое является 1/10
, может быть записано точно как [1 139]
0.1
в десятичном числе, или 0x1.99999999999999...p-4
в аналоге нотации C99 hexfloat, где эти ...
представляет бесконечную последовательность 9's. константы 0.2
и 0.3
в Вашей программе также будут приближениями к своим истинным значениям. Это происходит, что самое близкое double
к [1 115] больше, чем рациональное число 0.2
, но что самое близкое double
к [1 118] меньше, чем рациональное число 0.3
. Сумма [1 120] и 0.2
завершает то, чтобы быть больше, чем рациональное число 0.3
и следовательно не соглашающийся с константой в Вашем коде.
А довольно всесторонняя обработка арифметических проблем с плавающей точкой , Что Каждый Программист Должен Знать Об Арифметике С плавающей точкой . Для более легкого к обзору объяснения см. floating-point-gui.de .
Примечание Стороны: Все позиционные (основные-N) системы счисления совместно используют эту проблему с точностью
Простое десятичное число (базируйтесь 10), числа имеют те же проблемы, который является, почему числа как 1/3 заканчиваются как 0,333333333...
Вы только что наткнулись на номер (3/10), который, оказывается, легко представить с десятичной системой счисления, но не соответствует двоичной системе счисления. Это идет обоими путями (до некоторого маленького градуса) также: 1/16 является ужасным числом в десятичном числе (0.0625), но в двоичном файле это выглядит столь же аккуратным, как 10,000-е делает в десятичном числе (0.0001) ** - если бы мы имели привычку использовать основу 2 системы счисления в наших повседневных жизнях, то Вы даже посмотрели бы на то число и инстинктивно поняли бы, что могли прибыть туда путем сокращения вдвое чего-то, сокращения вдвое его снова, и снова и снова.
**, Конечно, это не точно, как числа с плавающей запятой хранятся в памяти (они используют форму экспоненциального представления). Однако это действительно иллюстрирует тезис, что двоичные ошибки точности с плавающей точкой имеют тенденцию неожиданно возникать, потому что числа "реального мира", с которыми мы обычно интересуемся работой, так часто полномочия десять - но только потому, что мы используем ежедневную десятичную систему счисления. Это также, почему мы скажем вещи как 71% вместо "5 из каждых 7" (71% приближение, так как 5/7 не может быть представлен точно ни с каким десятичным числом).
Так нет: двоичные числа с плавающей точкой не повреждаются, они просто, оказывается, так же несовершенны как любая основная-N система счисления:)
Примечание Стороны Стороны: Работая с Плаваниями в Программировании
На практике, эта проблема точности означает, что необходимо использовать округление функций для закругления чисел с плавающей точкой до однако многих десятичных разрядов, Вы интересуетесь тем, перед отображением их.
также необходимо заменить тесты равенства сравнениями, которые позволяют некоторый объем допуска, что означает:
Делают не , делают if (float1 == float2) { ... }
, Вместо этого делают if (Math.Abs(float1 - float2) < myToleranceValue) { ... }
.
myToleranceValue должен быть выбран для Вашего конкретного приложения - и это будет иметь много, чтобы сделать с тем, сколько "пространства для маневра" Вы готовы позволить, и что наибольшее число Вы собираетесь быть сравнением, может быть (из-за потери проблем точности). Остерегайтесь "дважды. Эпсилон" константы стиля на Вашем предпочтительном языке (Число. ЭПСИЛОН в JavaScript). Это не , чтобы использоваться в качестве значений допуска.
Ответ зависит от платформы. На большинстве платформ, если вывод из
readelf --relocs foo.o | egrep '(GOT|PLT|JU?MP_SLOT)'
пуст, то либо foo.o
не был скомпилирован с -fPIC
, либо foo.o
не скомпилирован содержать любой код, имеющий значение -fPIC
.
Мне просто нужно было сделать это на целевом компьютере PowerPC, чтобы определить, какой общий объект (.so) создавался без -fPIC. Я запустил readelf -d libMyLib1.so и поискал TEXTREL. Если вы видите TEXTREL, один или несколько исходных файлов, составляющих ваш .so, не были созданы с использованием -fPIC. Вы можете заменить readelf на elfdump , если необходимо.
Например,
[user@host lib]$ readelf -d libMyLib1.so | grep TEXT # Bad, not -fPIC
0x00000016 (TEXTREL)
[user@host lib]$ readelf -d libMyLib2.so | grep TEXT # Good, -fPIC
[user@host lib]$
И чтобы помочь людям искать решения, я получал следующую ошибку при запуске исполняемого файла:
root@target:/# ./program: error while loading shared libraries: /usr/lib/libMyLi
b1.so: R_PPC_REL24 relocation at 0x0fc5987c for symbol 'memcpy' out of range
Я не знаю, применима ли эта информация ко всем архитектурам.
Источник: blogs.oracle.com/rie
Другой вариант, позволяющий определить, создается ли ваша программа с параметром -fPIC:
при условии, что в вашем коде включена опция -g3 -gdwarf-2 при компиляции.
другой формат отладки gcc также может содержать информацию о макросе:
Обратите внимание, что следующий синтаксис $ '..' предполагает, что bash
echo $' main() { printf("%d\\n", \n#ifdef __PIC__\n__PIC__\n#else\n0\n#endif\n); }' | gcc -fPIC -g3
-gdwarf-2 -o test -x c -
readelf --debug-dump=macro ./test | grep __PIC__
такой метод работает, потому что руководство gcc объявляет, что если используется -fpic, PIC определяется как 1, а если используется -fPIC, PIC равно 2.
Приведенные выше ответы с проверкой GOT - лучший способ. Поскольку предварительный запрос -g3 -gdwarf-2, я думаю, используется редко.