Я заметил, что согласно Lua, 2 ~= math.sqrt(2) ^ 2
print(2 == math.sqrt(2) ^ 2) --> false
print(2, math.sqrt(2) ^ 2) --> 2 2
Почему это происходит?
Я заметил, что согласно Lua, 2 ~= math.sqrt(2) ^ 2
print(2 == math.sqrt(2) ^ 2) --> false
print(2, math.sqrt(2) ^ 2) --> 2 2
Почему это происходит?
Большинство чисел с плавающей запятой не могут быть сохранены именно в числовом типе Lua (по умолчанию C double
). math.sqrt(2)
является одним из них.
Если вы пытаетесь:
print(2 - math.sqrt(2) ^ 2)
Выход: -4.4408920985006e-016
, что является очень маленьким числом, но тем не менее делает два числа не совсем эквивалентными.
Эта проблема точности с плавающей запятой существует не только в Lua, но и во многих других языках. Как комментирует @Thilo, вы можете использовать небольшую «дельту» при сравнении на равенство на практике. Вам могут быть интересны: Часто задаваемые вопросы по языку C: как проверить плавающее положение "достаточно близко"? равенство точек?.
tostring(0.000000000000000000001) -> 1e-021
- person doog abides; 20.11.2014
double
в C, Lua использует формат "%.14g"
для печати чисел по умолчанию, если я правильно помню.
- person Yu Hao; 20.11.2014
Следующее рассуждение показывает, что в общем случае sqrt(x)*sqrt(x) == x
невозможно удерживать для всех операндов в арифметике с плавающей запятой, будь то двоичная или десятичная, даже если операция извлечения квадратного корня возвращает правильно округленные результаты (как это обычно бывает на современных компьютерах). которые соответствуют стандарту IEEE-754 с плавающей запятой).
В двоичном представлении с плавающей запятой конечной точности каждая бинада (пространство между двумя последовательными степенями числа 2) содержит одно и то же количество точно представляемых чисел. Для одинарной точности IEEE-754 на двоичную группу приходится 223 таких машинных номеров, для двойной точности IEEE-754 таких номеров на одну двоичную группу приходится 252.
Квадратный корень — это сжимающая операция, поскольку она отображает входную область из двух бинад, скажем, [1,4], в результирующий диапазон только из одного бинада, скажем, [1,2). Таким образом, в случае операндов двойной точности IEEE-754 253 возможных аргументов функции в двух бинадах сопоставляются не более чем с 252 различными результатами квадратного корня. Если теперь возвести в квадрат результаты операции извлечения квадратного корня, мы получим не более 252 различных произведений, распределенных по двум двоичным числам, которые могут представлять 253 числа машин.
Следовательно, равенство sqrt(x)*sqrt(x) == x
может выполняться не более чем для половины возможных входных данных с плавающей запятой. Экспериментально можно показать, что оно выполняется ровно для половины входов от двух бинад.
С другой стороны, равенство x == sqrt (x * x)
выполняется в арифметике с плавающей запятой IEEE-754 при условии, что при вычислении продукта нет промежуточного переполнения или потери значимости.
Природа арифметики с плавающей запятой очень важна в общих средах программирования. Программы статического анализа исходного кода классического C (например, «lint») фактически выдадут вам предупреждение, если вы используете реляционные операторы для чисел с плавающей запятой. Как уже говорили другие, мы допускаем терпимость в сравнениях.
Однако пример, который вы выбрали, √2, иррационален. Никакая вычислительная система счисления не может удержать это число. Оно может быть точным только как символическое выражение. Доступно несколько систем символьного программирования: Octave-Symbolic, MathCAD, MATLAB, ... и теперь Wolfram (я думаю). Они сохранят √2 как выражение и оценят √2 * √2 как ровно 2.
q x-p=0
, решением которого является p/q. Квадратный корень из 2 можно представить в виде многочлена x^2-2=0
. Алгебраические числа обладают хорошими свойствами, их можно складывать, умножать и делить.
- person Salix alba; 23.11.2014