Потеря точности - int - > плавать или двойной

У меня есть экзаменационный вопрос, который я пересматриваю, и вопрос для 4 баллов.

«В Java мы можем присвоить int двойному или плавающему». Будет ли это когда-либо терять информацию и почему?

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

Теперь я немного отрывочен относительно того, бью ли я здесь нужные области. Я уверен, что он потеряет точность, но я не могу точно понять, почему. Могу ли я получить помощь, пожалуйста?

23
задан pjs 15 May 2015 в 14:29
поделиться

6 ответов

Нет необходимости знать внутреннее расположение чисел с плавающей точкой. Все, что вам нужно, - это принцип квадратного отверстия и знание того, что int и float имеют одинаковый размер.

  • int - это 32-битный тип, для которого каждая битовая комбинация представляет отдельное целое число, поэтому существует 2 ^ 32 int значений.
  • float является 32-битным типом, поэтому он имеет не более 2 ^ 32 различных значений.
  • Некоторые float представляют нецелые числа, поэтому меньше , чем 2 ^ 32 float значений, которые представляют целые числа.
  • Следовательно, различные значения int будут преобразованы в одно и то же значение float (= потеря точности).

Аналогичные рассуждения могут быть использованы с long и double.

24
ответ дан Julien Kronegg 15 May 2015 в 14:29
поделиться

Нет, float и double тоже фиксированной длины - они просто используют свои биты по-разному. Узнайте больше о том, как именно они работают, в Floating-Poing Guide .

По сути, вы не можете потерять точность при назначении int для double, потому что double имеет 52 биты точности, которых достаточно для хранения всех int значений. Но float имеет только 23 бита точности, поэтому он не может точно представить все int значения, которые больше, чем примерно 2 ^ 23.

13
ответ дан Michael Borgwardt 15 May 2015 в 14:29
поделиться

Ваша интуиция верна, вы МОЖЕТЕ потерять точность при преобразовании int в float. Однако это не так просто, как представлено в большинстве других ответов.

В Java FLOAT использует 23-битную мантиссу, поэтому у целых чисел больше 2 ^ 23 их младшие биты будут усечены. (из поста на этой странице)

Не соответствует действительности.
Пример: здесь целое число больше 2 ^ 23, которое преобразуется в число с плавающей точкой без потерь:

int i = 33_554_430 * 64; // is greater than 2^23 (and also greater than 2^24); i = 2_147_483_520
float f = i;
System.out.println("result: " + (i - (int) f)); // Prints: result: 0
System.out.println("with i:" + i + ",  f:" + f);//Prints: with i:2_147_483_520,  f:2.14748352E9

Следовательно, неверно, что целые числа больше 2 ^ 23 будут иметь свои младшие значащие биты усеченный. [+1122]

Лучшее объяснение, которое я нашел, это здесь:
Число с плавающей точкой в ​​Java является 32-битным и представлено:
знак * мантисса * 2 ^ экспонента
знак * (от 0 до 33_554_431) * 2 ^ (- от 125 до +127)
Источник: http://www.ibm.com/developerworks/java/library/j -math2 / index.html

Почему это проблема?
Создается впечатление, что вы можете определить, есть ли потеря точности из int плавать , просто посмотрев, насколько велико int.
Я особенно видел экзаменационные вопросы по Java, где спрашивают, превратится ли большое int в float без потерь.

Кроме того, иногда люди склонны думать, что будет потеря точности от int до float:
, когда int больше чем: 1_234_567_890 не верно (см. Counter - пример выше)
, когда int больше, чем: 2 экспонента 23 (равно: 8_388_608) не верно
, когда int больше чем: 2 показатель степени 24 (равно: 16_777_216) не соответствует действительности

Заключение
Преобразования из достаточно больших целых чисел в числа с плавающей точкой МОГУТ потерять точность.
Невозможно определить, будут ли убытки, просто посмотрев , насколько велико значение int (т.е. не пытаясь углубиться в реальное представление с плавающей точкой).

4
ответ дан Julien Kronegg 15 May 2015 в 14:29
поделиться

Есть две причины, по которым присваивание типа int двойному или плавающему может потерять точность:

  • Существуют определенные числа, которые просто не могут быть представлены как двойные / плавающие, поэтому они заканчиваются с точностью до аппроксимации
  • Большие целые числа могут содержать слишком большую точность в значимых для аренды цифрах
1
ответ дан Adam Batkin 15 May 2015 в 14:29
поделиться

Вот что говорит JLS по этому вопросу (в нетехническом обсуждении).

JLS 5.1.2 Расширяющее примитивное преобразование

Следующие 19 конкретных преобразований примитивных типов называются расширяющимися примитивными преобразованиями:

  • int long, float или double
  • (без учета опущенных)

Преобразование значения int или long в float или значение от long до double может привести к потере точности , то есть результат может потерять некоторые из младших значащих битов значения. В этом случае результирующее значение с плавающей запятой будет правильно округленной версией целочисленного значения с использованием режима округления до ближайшего стандарта IEEE 754.

Несмотря на то, что может произойти потеря точности, расширяющиеся преобразования среди примитивных типов никогда не приводят к исключению во время выполнения.

Вот пример расширяющегося преобразования, которое теряет точность:

class Test {
         public static void main(String[] args) {
                int big = 1234567890;
                float approx = big;
                System.out.println(big - (int)approx);
        }
}

, которое печатает:

-46

, что указывает на то, что информация была потеряна во время преобразования из типа int чтобы ввести float, потому что значения типа float не являются точными до девяти значащих цифр.

18
ответ дан polygenelubricants 15 May 2015 в 14:29
поделиться

Возможно, самое ясное объяснение, которое я видел: http://www.ibm.com/developerworks/java/library/j-math2/index.html ULP или единица наименьшей точности определяет Точность доступна между любыми двумя значениями с плавающей запятой. По мере увеличения этих значений доступная точность уменьшается. Например: между 1,0 и 2,0 включительно имеется 8 388 609 чисел с плавающей запятой, между 1 000 000 и 1 000 001 - 17. При 10 000 000 ULP составляет 1,0, поэтому выше этого значения у вас скоро будет несколько целочисленных значений, сопоставляемых каждому доступному числу с плавающей запятой, что приводит к потере точности.

4
ответ дан Ian MacMillan 15 May 2015 в 14:29
поделиться