Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Сравнение вещественных примитивов

Читайте также:
  1. Значимость каждой характеристики для всех исследуемых сайтов должна быть одинакова, иначе сравнение невозможно.
  2. Краткая характеристика и сравнение Израильского и Иудейского царств
  3. Сравнение
  4. Сравнение Гейдельбергского катехизиса с Лютеранским и Вестминстерским катехизисами
  5. СРАВНЕНИЕ ДЕСЯТИЧНЫХ ДРОБЕЙ
  6. СРАВНЕНИЕ ИДЕЙ

Для начала я хочу задать вопрос. Очень простой. Чему равна следующая сумма – 0.3f + 0.4f? Чему?0.7f? Проверим:

float f1 = 0.7f; float f2 = 0.3f + 0.4f;System.out.println("f1==f2: "+(f1==f2));

Как результат? Нравится? Мне тоже. Для тех, кто не выполнил этот фрагмент, скажу – результат будет...

f1==f2: false

Почему это происходит?.. Выполним еще один тест:

float f1 = 0.3f; float f2 = 0.4f; float f3 = f1 + f2; float f4 = 0.7f;System.out.println("f1="+(double)f1);System.out.println("f2="+(double)f2);System.out.println("f3="+(double)f3);System.out.println("f4="+(double)f4);

Обратите внимание на приведение к double. Это сделано для того, чтобы вывести побольше знаков после запятой.Результат:

f1=0.30000001192092896f2=0.4000000059604645f3=0.7000000476837158f4=0.699999988079071

Собственно говоря, результат прогнозируемый. Представление дробной части осуществляется с помощью конечного ряда2-n, а потому о точном представлении произвольно взятого числа говорить не приходится. Как видно из примера,точность представления float – 7 знаков после запятой.

Строго говоря, в представлении float на мантиссу отведено 24 бита. Таким образом минимальное по модулю число, которое можно представить с помощью float (без учета степени, ибо мы говорим о точности) – это2-24≈6*10-8. Именно с таким шагом реально идут значения в представлении float.А поскольку есть квантование – есть и погрешность.

Отсюда вывод: числа в представлении float можно сравнивать только с определенной точностью. Я бы рекомендовал округлять их до 6-го знака после запятой (10-6), либо, что предпочтительнее, проверял бы абсолютное значение 2 разности между ними:

float f1 = 0.3f; float f2 = 0.4f; float f3 = f1 + f2; float f4 = 0.7f;System.out.println("|f3-f4|<1e-6: "+(Math.abs(f3-f4) < 1e-6));

В этом случае результат вселяет надежду:

|f3-f4|<1e-6: true

Разумеется, точно та же картина и с типом double. С единственной разницей, что там на мантиссу отведено 53бита, следовательно, точность представления – 2-53≈10-16. Да, величина квантования куда меньше, но она есть. И может сыграть злую шутку.

Кстати, в тестовой библиотеке JUnit в методах сравнения вещественных чисел точность указывается в явном виде. Т.е. метод сравнения содержит три параметра – число, чему оно должно быть равно и точность сравнения.

Еще кстати, хочу упомянуть о тонкости, связаной с записью чисел в научном формате, с указанием степени.Вопрос. Как записать 10-6? Практика показывает, что более 80% отвечают – 10e-6. Между тем, правильный ответ – 1e-6! А 10e-6 – это 10-5! Мы наступили на эти грабли в одном из проектов,довольно неожиданно. Ошибку искали очень долго, на константы смотрели раз 20. И ни у кого не возникло ни тени сомнения в их правильности, пока однажды, в большой степени случайно, константу 10e-3 не вывели на печать и не обнаружили у нее после запятой два знака вместо ожидавшихся трех. А потому – будьте бдительны!

Движемся дальше.

И -0.0

В представлении вещественных чисел старший бит является знаковым. А что будет, если все остальные биты равны 0? В отличие от целых, где в такой ситуации получается отрицательное число, находящееся на нижней границе диапазона представления, вещественное число только со старшим битом, выставленным в 1, тоже обозначает 0,только со знаком минус. Таким образом, у нас есть два нуля – +0.0 и -0.0.

Возникает логичный вопрос – считать ли эти числа равными? Виртуальная машина считает именно так. Однако, это два разных числа, ибо в результате операций с ними получаются разные значения:

float f1 = 0.0f/1.0f; float f2 = 0.0f/-1.0f;System.out.println("f1="+f1);System.out.println("f2="+f2);System.out.println("f1==f2: "+(f1==f2)); float f3 = 1.0f / f1; float f4 = 1.0f / f2;System.out.println("f3="+f3);System.out.println("f4="+f4);

... и результат:

f1=0.0f2=-0.0f1==f2: truef3=Infinityf4=-Infinity

Таким образом, в некоторых случаях есть смысл расценивать +0.0 и -0.0 как два разных числа.А если у нас есть два объекта, в одном из которых поле равно +0.0, а в другом -0.0 – эти объекты точно так же можно расценивать как неравные. Возникает вопрос – а как понять, что числа неравны, если их прямое сравнение виртуальной машиной дает true?

Ответ таков. Несмотря на то, что виртуальнай машина считает эти числа равными, представления у них все-таки отличаются.Поэтому – единственное, что можно сделать, это сравнить представления. А для того, чтобы его получить, существуют методыint Float.floatToIntBits(float) и long Double.doubleToLongBits(double), которые возвращают битовое представление в виде int и long соответственно (продолжение предыдущего примера):

int i1 = Float.floatToIntBits(f1); int i2 = Float.floatToIntBits(f2);System.out.println("i1 (+0.0):"+ Integer.toBinaryString(i1));System.out.println("i2 (-0.0):"+ Integer.toBinaryString(i2));System.out.println("i1==i2: "+(i1 == i2));

Результатом будет

i1 (+0.0):0i2 (-0.0):10000000000000000000000000000000i1==i2: false

Таким образом, если у вас +0.0 и -0.0 – разные числа, то сравнивать вещественные переменные следует через их битовое представление.

С +0.0 и -0.0 вроде как разобрались. -0.0, однако, является не единственным сюрпризом. Есть еще такое явление как...

 


Дата добавления: 2015-10-21; просмотров: 75 | Нарушение авторских прав


Читайте в этой же книге: One pint of used oil can cover one acre of water surface and kill sensitive marinecreatures. . . | Tips to Protect Children from Pesticide and Lead Poisonings | Eco-Friendly Tips |
<== предыдущая страница | следующая страница ==>
Вещественный тип данных| Do something

mybiblioteka.su - 2015-2024 год. (0.006 сек.)