Логически сомнительно?

#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!)
  • С точки зрения разработки программного обеспечения тот факт, что вам нужно проводить индивидуальный анализ == использования, делает его сомнительной практикой. Хорошая разработка программного обеспечения (частично) заключается в устранении ошибок и источников ошибок.