2016-02-19 5 views
0

Почему нижнее округление не работает в python 3, но только в python 2?Python 3 rounding issue

random_nums = np.array([-1, 0, 1, 2, 3]) 
probabilities = np.array([0.01, 0.3, 0.58, 0.1, 0.01]) 
target = dict(zip(random_nums, probabilities)) 
target = {k: round(v, 2) for k, v in target.items()} 

out: 
{-1: 0.01, 
0: 0.29999999999999999, 
1: 0.57999999999999996, 
2: 0.10000000000000001, 
3: 0.01} 
+0

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

ответ

3

Вы работаете с объектами NumPy float64 вместо Python float объектов. Это имеет несколько последствий:

  1. На Python 3, float64 объектов закруглены с использованием Numpy округления коды вместо языка Python. Код округления Python для float s всегда дает правильно округленные результаты. Код округления NumPy не работает. (В Python 2 переопределить операцию round для настраиваемых типов невозможно, поэтому, когда вы округляете объект float64 в Python 2, он сначала преобразуется в Python float, а затем код округления Python используется для получения результата float. является основной причиной того, что вы видите разницу между Python 2 и Python 3.)

  2. снова на Python 3, из вышеизложенного, round на float64 дает float64 результат. На Python 2, round на объекте float64 появляется результат float.

  3. Python float Объекты имеют разные repr, что даст выходной сигнал pleasanter. В частности, поплавок Python repr гарантирует округление в течение (не слишком больших, не слишком малых) десятичных значений с не более чем 15 значащими цифрами: например, 0.58 - '0.58'. Представление объектов NumPy float64 не имеет этого свойства: оно просто распечатывает результат на основе наиболее значимых 17 десятичных цифр хранимого значения.

Так что, если вам конвертировать значения в Python float объектов до раунда, вы увидите приятней выход (а в некоторых случаях результаты могут быть чуть-чуть более точными). Но обратите внимание, что только потому, что вывод выглядит неплохо, это не значит, что результаты, которые вы получаете, точны. Ничто из этого не меняет того факта, что 0.58не, точно представляемый как Python float (или действительно NumPy float64, который использует тот же формат). Помните, что с бинарной точкой с плавающей точкой, что вы видите, не то, что вы получаете.

Некоторых примеров вывод на Python 3:

>>> random_nums = np.array([-1, 0, 1, 2, 3]) 
>>> probabilities = np.array([0.01, 0.3, 0.58, 0.1, 0.01]) 
>>> target = dict(zip(random_nums, probabilities)) 
>>> {k: round(v, 2) for k, v in target.items()} 
{0: 0.29999999999999999, 1: 0.57999999999999996, 2: 0.10000000000000001, 3: 0.01, -1: 0.01} 
>>> {k: round(float(v), 2) for k, v in target.items()} 
{0: 0.3, 1: 0.58, 2: 0.1, 3: 0.01, -1: 0.01} 
0

Кажется, что он работает нормально. Помните, что round возвращает число с плавающей запятой.

Он округлен до двух знаков после запятой, но поплавки по своей сути являются inprecise (почти для всех чисел), следовательно, выход.

+0

что это лучший способ решить эту проблему? – Nickpick

+0

...... решить что? –

+0

, поэтому вывод выглядит неплохо и имеет только 2 десятичных знака. – Nickpick