Целые числа и точность с плавающей точкой - PullRequest
4 голосов
/ 15 декабря 2009

Это скорее числовой анализ, нежели вопрос программирования, но я полагаю, что некоторые из вас смогут ответить на него.

В сумме двух поплавков потеряна ли точность? Почему?

В сумме значений с плавающей точкой и целого числа потеряна ли точность? Почему?

Спасибо.

Ответы [ 9 ]

7 голосов
/ 15 декабря 2009

В сумме двух поплавков потеряна ли точность?

Если оба числа имеют разную величину и оба используют полный диапазон точности (около 7 десятичных цифр), тогда да, вы увидите некоторые потери в последних местах.

Почему?

Это потому, что числа с плавающей запятой хранятся в форме (знак) (мантисса) × 2 (показатель степени) . Если два значения имеют разные показатели, и вы добавляете их, то меньшее значение будет уменьшено до меньшего числа в мантиссе (поскольку оно должно адаптироваться к большему показателю):

PS> [float]([float]0.0000001 + [float]1)
1

В сумме значений с плавающей точкой и целого числа потеряна ли точность?

Да, обычное 32-разрядное целое число способно представлять значения, которые точно не вписываются в число с плавающей точкой. Число с плавающей точкой все еще может хранить приблизительно того же числа, но уже не точно. Конечно, это относится только к числам, которые достаточно велики, т.е. е. длиннее 24 бит.

Почему?

Поскольку float имеет 24-битную точность, а (32-битные) целые имеют 32. float по-прежнему сможет сохранять величину и большинство значащих цифр, но последние места могут отличаться:

PS> [float]2100000050 + [float]100
2100000100
3 голосов
/ 15 декабря 2009

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

3.12000000000 * 10 ^ 2

Десятичные разряды в левой части (мантисса) фиксированы. Показатель степени также имеет верхнюю и нижнюю границы. Это позволяет ему представлять очень большие или очень маленькие числа.

Если вы попытаетесь добавить два одинаковых по величине числа, результат должен остаться одинаковым по точности, потому что десятичная точка не должна двигаться:

312.0 + 643.0 <==>

3.12000000000 * 10 ^ 2 +
6.43000000000 * 10 ^ 2
-----------------------
9.55000000000 * 10 ^ 2

Если вы попытаетесь добавить очень большое и очень маленькое число, вы потеряете точность, потому что они должны сжаться в указанном выше формате. Рассмотрим 312 + 12300000000000000000000. Сначала вам нужно масштабировать меньшее число, чтобы выровнять с большим, а затем добавить:

1.23000000000 * 10 ^ 15 +
0.00000000003 * 10 ^ 15
-----------------------
1.23000000003 <-- precision lost here!

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

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

2 голосов
/ 15 декабря 2009

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

При добавлении числа с плавающей точкой к целому числу, целое число сначала преобразуется в число с плавающей точкой с помощью C ++, поэтому добавляются два числа с плавающей точкой и появляется ошибка по тем же причинам, что и выше.

1 голос
/ 15 декабря 2009

В сумме двух поплавков потеряна ли точность? В сумме чисел с плавающей точкой и целого числа потеряна ли точность? Почему?

Не всегда. Если сумма представляется с точностью, которую вы запрашиваете, и вы не получите никакой потери точности.

Пример: 0,5 + 0,75 => нет потери точности x * 0.5 => нет потери точности (кроме случаев, когда x слишком мал)

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

Денормали здесь, чтобы обеспечить сверхточность в экстремальных случаях за счет ЦП.

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

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

1 голос
/ 15 декабря 2009

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

Если вы попытаетесь добавить (скажем) 10 ^ 23 и 7, то он не сможет точно представить этот результат. Аналогичный аргумент применяется при добавлении числа с плавающей точкой и целого числа - целое число будет преобразовано в число с плавающей точкой.

1 голос
/ 15 декабря 2009

Точность, доступная для float, ограничена, поэтому, конечно, всегда есть риск того, что любая операция снизит точность.

Ответ на оба ваших вопроса "да".

Если вы попытаетесь добавить очень большое число с плавающей точкой к очень маленькому, у вас, например, будут проблемы.

Или если вы попытаетесь добавить целое число в число с плавающей точкой, где целое число использует больше битов, чем число с плавающей точкойИмеется в наличии для своей мантиссы.

0 голосов
/ 15 декабря 2009

В обоих случаях ответ «да». При добавлении int к float целое число преобразуется в представление с плавающей запятой, прежде чем добавление все равно произойдет.

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

0 голосов
/ 15 декабря 2009

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

0 голосов
/ 15 декабря 2009

В обоих случаях да:

assert( 1E+36f + 1.0f == 1E+36f );
assert( 1E+36f + 1 == 1E+36f );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...