Подтвердить что ты не робот

Потеря точности - int → float или double

У меня вопрос экзамена, на который я пересматриваю, и вопрос заключается в 4-х знаках.

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

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

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

4b9b3361

Ответ 1

В Java Integer использует 32 бита для представления своего значения.

В Java FLOAT использует 23-битную мантиссу, поэтому целые числа, превышающие 2 ^ 23, будут усекаться по наименьшим значащим битам. Например, 33554435 (или 0x200003) будет усечен примерно до 33554432 +/- 4

В Java DOUBLE использует 52-битную мантиссу, поэтому сможет представлять 32-битное целое число без потери данных.

См. также " Плавающая точка" на wikipedia

Ответ 2

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

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

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

Ответ 3

Здесь 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 не точны до девяти значащих цифр.

Ответ 4

Нет, float и double тоже фиксированные длины - они просто используют свои биты по-разному. Подробнее о том, как именно они работают в Руководство по плавающим Poing.

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

Ответ 5

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

Ответ 6

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

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

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

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, усекают наименее значимые биты.

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

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

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

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

Ответ 7

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

  • Есть определенные числа, которые просто не могут быть представлены как double/float, поэтому они заканчиваются аппроксимированными
  • Большие целые числа могут содержать слишком большую точность в значимых для аренды цифрах.

Ответ 8

В этих примерах я использую Java.

Используйте такую ​​функцию, чтобы проверить на потерю точности при литье из int в float

static boolean checkPrecisionLossToFloat(int val)
{
  if(val < 0)
  {
    val = -val;
  }
  // 8 is the bit-width of the exponent for single-precision
  return Integer.numberOfLeadingZeros(val) + Integer.numberOfTrailingZeros(val) < 8;
}

Используйте функцию, подобную этой, чтобы проверить потерю точности при литье из длинного в двойное

static boolean checkPrecisionLossToDouble(long val)
{
  if(val < 0)
  {
    val = -val;
  }
  // 11 is the bit-width for the exponent in double-precision
  return Long.numberOfLeadingZeros(val) + Long.numberOfTrailingZeros(val) < 11;
}

Используйте такую ​​функцию, чтобы проверить потерю точности при литье из long to float

static boolean checkPrecisionLossToFloat(long val)
{
  if(val < 0)
  {
    val = -val;
  }
  // 8 + 32
  return Long.numberOfLeadingZeros(val) + Long.numberOfTrailingZeros(val) < 40;
}

Для каждой из этих функций возвращение true означает, что приведение этого интегрального значения в значение с плавающей запятой приведет к потере точности.

Листинг для float потеряет точность, если интегральное значение имеет более 24 значащих бит.

Литье в два раза будет терять точность, если интегральное значение имеет более 53 значащих бит.