#java
#java
Вопрос:
double x = 1;
double y = 3 * (1.0 / 3);
x == y
В powerpoint, который я изучаю, говорится, что утверждение логически сомнительно. Я не могу понять, почему это так, я имею в виду, что вы используете == для правильных примитивов, или это логически сомнительно, потому что двойники хранятся не точно или я упускаю что-то очевидное? Спасибо
Комментарии:
1. Разве удвоения не включают десятичные дроби, а 1 и 3 — нет?
2. Это последнее. Двойные значения имеют ограниченную точность, и ошибки округления накапливаются.
3. Какое утверждение логически сомнительно? Выражение сравнения логически сомнительно, потому что вы нигде не используете результат.
Ответ №1:
Я думаю, вы поняли: поскольку типы данных являются double , а не int или Integer , результирующие x и y могут быть не совсем равными.
Комментарии:
1. я собирался ответить, когда увидел это, поэтому подумал, что добавлю к нему. его использование «double» делает его сложным! нет никакой гарантии, что это всегда будет оцениваться как true. y может быть 0,9999 или 1,00001
2. Прохладный. Я думаю, что ответ Джонатана Ньюмуиса в любом случае лучше моего.
3. Если вы используете
int
3*(1/3) != 1. 😉
Ответ №2:
Это логически сомнительно, потому что оператор сравнения в конце будет иметь значение false . Удвоения хранятся в виде последовательности степеней двойки. Таким образом, такие значения, как 1/2, 1/4 и 1/8, на самом деле могут быть точно выражены в форматах с плавающей запятой, но не 1/3. Оно будет приближено к 1/4 1/64 … теперь есть способ, которым это может быть примерно 1/3
Правильный способ сравнения чисел с плавающей точкой выглядит следующим образом:
Math.double.abs ( x - y ) > tol
где tol устанавливается на что-то достаточно маленькое, в зависимости от вашего приложения. Например, большинство графических приложений хорошо работают с tol = 0.00001
Ответ №3:
Потому 1.0 / 3
что это 0.3333...
, до емкости a double
. 3 * 0.3333...
это 0.9999...
, вплоть до емкости double.
Итак, у нас есть вопрос 1 == 0.9999...
, который, я думаю, вы могли бы назвать «логически сомнительным».
Комментарии:
1. Осторожно — на самом
1
деле равно0.999...
2.
1
равно0.999...
, где существует бесконечное число 9. Но это не бесконечное число 9, поэтому в этом случае они не будут равны. Но, как упоминали здесь другие, все зависит от округления в два раза.
Ответ №4:
Это из-за ошибки округления. Проблема аналогична проблемам точности, с которыми вы сталкиваетесь с десятичными дробями при работе с числами, которые не могут быть точно выражены в используемом вами формате.
Например, при шестизначной десятичной точности лучшее, что вы можете сделать для 1/3, это .333333
. Но:
1/3 1/3 1/3
-> .33333 .333333 .33333 = .999999 != 1.000000
Ой. Для 2/3 вы можете использовать либо .666666
или .666667
, но в любом случае у вас возникают проблемы.
Если 2/3 -> .666666
тогда:
2/3 1/3
-> .333333 .666666 != 1.000000
Ой.
И если 2/3. -> .666667
тогда:
1/3 * 2 - 2/3
-> .333333 * 2.00000 — .666667 = .666666 — .666667 != 0
Ой.
Это аналогично с удвоениями. Эта статья считается авторитетной работой по этому вопросу. Проще говоря — никогда не сравнивайте числа с плавающей запятой на равенство, если вы точно не знаете, что делаете.
Комментарии:
1. правильно. числа с плавающей запятой и удвоения хранятся как степени 2, а не как десятичные дроби. Что сделает ситуацию еще хуже в случае 1/3.
Ответ №5:
Логически сомнительно, потому что двойные значения хранятся не точно
Более или менее.
- Как правило, a
double
не может представлять точное значение действительного числа. Значение1/3
является примером. - Некоторые числа могут быть представлены точно как
double
значения.1.0
и3.0
примеры. Однако оператор деления выдает число (в данном случае), которое не может быть представлено. - В общем, любой код, который используется
==
для сравненияdouble
float
значений or, вызывает сомнение … в том смысле, что вам нужно тщательно проанализировать каждый случай, чтобы узнать, правильно ли используется==
. (И анализ не интуитивно понятен для людей, которых в очень раннем возрасте учили делать арифметику в базе 10!) - С точки зрения разработки программного обеспечения тот факт, что вам нужно проводить индивидуальный анализ
==
использования, делает его сомнительной практикой. Хорошая разработка программного обеспечения (частично) заключается в устранении ошибок и источников ошибок.