2012-07-12 2 views
2

Я использую jdk 1.6. Это мой код.Java float и double diff

float f = 10.0f; 

double d = 10.0; 

System.out.println("Equal Status : " + (f == d)); 

то система показывает ответ как true. Но если бы я изменил значение как

float f = 10.1f; 

double d = 10.1; 

System.out.println("Equal Status : " + (f == d)); 

тогда система ответила как ложь. Я знаю, что система использует бит для проверки ==. Но в чем причина. Вы можете объяснить об этом? Заранее спасибо.

+2

.1 не может быть представлен конечными значащими цифрами в двоичном представлении, например, как 1/3 не может быть представлено конечными значащими цифрами в десятичной форме. – nhahtdh

ответ

1

Хотя это не «мой» ответ, это примерно так же, как «нужно читать» литературу для программистов, которые хотят перейти от «meh» к «good». Великий - это что-то действительно особенное, поэтому не думайте, что «хороший» - это что-то, что можно было чихнуть. :)

What Every Programmer Needs to know about Floating Point

0

float - 32-разрядный тип, тогда как double - это 64-разрядный тип.

Вы столкнулись с проблемой точности с плавающей запятой.

0

Поплавки неточны. Фактические значения 10.1f и 10.1 будут немного отличаться из-за округления. Поплавки двоичные, а не десятичные, поэтому числа, которые выглядят «просто» для нас, например 10.1, не могут быть представлены точно как плавающие.

+0

Возможно, вы имели в виду 10.1? – nhahtdh

+0

@Ned --- Вы сказали, что фактические значения 10.0f и 10.0 будут разными, но согласно OP он показывает true, что означает, что они одинаковы. Так что это не повод для его вопроса. –

+0

К сожалению, да, 10.1 –

1

Ссылка @ Сэм предложил велик, но все еще слишком технический для меня: P

Я просто приведу некоторые мнения в ОП для обработки чисел с плавающей точкой (возможно, немного не по теме, потому что вы просите причину. По этой причине прочитайте ссылку @Sam).

Никогда не предполагайте, что число с плавающей точкой будет давать вам точные изображения. Иногда это может, но не всегда. Плавающая точка имеет свое ограничение в «значимых цифрах», которое является «точной» для первой n-й цифры.

Ваша ситуация еще хуже, потому что вы смешиваете float и double, но идея решить аналогична.

Вам необходимо решить, для какой точности вашему приложению нужен результат вычисления, и принять решение о его базе значений Epsilon. Например, ваше приложение нуждается только в точности до 3 знаков после запятой, вероятно, Epsilon 0,0005 является разумным.

Сравнение двух чисел с плавающей запятой не должно быть сделано ==, вы должны использовать (a + EPSILON > b && a - EPSILON < b). Аналогично, a > b следует указывать как a - EPSILON > b

+0

HA! Нет аргументов. Конечно, я не проверю все моменты. – Sam

0

Вы хотите обновить себя на IEEE floating point standards для 32 и 64-разрядных представлений с плавающей запятой. Если вы очистите внутренности от этого, вы ясно увидите, почему эти точки с плавающей запятой ведут себя весьма искусно.

Если вам интересно, как он представлен внутри страны (именно поэтому он не работает), вы можете использовать этот код, который показывает шестнадцатеричные представления этих чисел. Оттуда вы можете сопоставить их с показателями и мантиссами одинарной и двойной точности.

System.out.printf("Float 10.0: 0x%X\n", Float.floatToRawIntBits((float)10.0)); 
System.out.printf("Double 10.0: 0x%X\n", Double.doubleToRawLongBits(10.0)); 
System.out.printf("Float 10.1: 0x%X\n", Float.floatToRawIntBits((float)10.1)); 
System.out.printf("Double 10.1: 0x%X\n", Double.doubleToRawLongBits(10.1)); 

печатает

Float 10.0: 0x41200000 
Double 10.0: 0x4024000000000000 
Float 10.1: 0x4121999A 
Double 10.1: 0x4024333333333333 

Вы заметите, что есть некоторые повторения в пути представлены значения. Это потому, что 1/10 can't be represented in a finite space of base 2.

1

Очки помнить являются

  1. 10.1 повторяющаяся последовательность в двоичном 1010101010 ......
  2. При сравнении с плавающей точкой и двойной поплавок преобразуется в двойной путем добавления ZERRO-х чтобы заполнить номер из

    так что вы будете сравнивать

    1010101 ... 00000000 ... до 1010101 ..... 101010 ... которые различны.

    float f = 10.1f;

    double d = 10.1;

    System.out.println ("Equal Status:" + (f == (float) d));

даст ответ истинного

1

ИМХО, вообще говоря, 99% случае использования double является лучшим выбором, поскольку он является более точным. т. е. не использовать float, если вам не нужно.

BigDecimal может использоваться для отображения фактического представления float или double. Вы не видите это, как правило, как toString будет выполнять небольшое количество округления (как кодируется для размещения ограничения типов представительские)

System.out.println("10.1f is actually " + new BigDecimal(10.1f)); 
System.out.println("10.1 is actually " + new BigDecimal(10.1)); 

печатает

10.1f is actually 10.1000003814697265625 
10.1 is actually 10.0999999999999996447286321199499070644378662109375 

Вы можете видеть, что double значение ближе к желаемому 10.1, но не точно это значение. Причина, по которой эти значения различны, заключается в том, что в каждом случае она имеет самое близкое значение для этого типа.

Смежные вопросы