Целочисленное деление питон: Целочисленное деление в Python

Оператор деления в Python: примеры с описанием

Главная » Числа, даты и время Python

0

Python поддерживает два оператора деления: / и //. На самом деле за этим стоит целая история. В первых выпусках Python был только один оператор деления (/). Однако его работа была неоднозначной. Для целых чисел он раньше возвращал целочисленное значение, тогда как для чисел с плавающей запятой он возвращал значения с плавающей запятой. В Python не было оператора истинного деления.

Чтобы исправить это – Python 2.2 представил новый оператор деления (//) и позволил разработчикам переносить свои приложения, чтобы использовать его везде, где им нужно целочисленное деление. Это изменение было выполнено в соответствии с PEP-238. Наконец, в Python 3 оператор деления (/) начал работать, как оператор истинного деления.

Давайте рассмотрим несколько простых фрагментов кода, чтобы понять операторы деления в Python.

Операторы деления в Python 2

$ python2.7
Python 2.7.10 (default, Aug 17 2018, 19:45:58) 
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 9/2
4
>>> -9/2
-5
>>> 9.0/2
4.5
>>> -9.0/2
-4.5
>>> 9//2
4
>>> -9//2
-5
>>> 9.0//2
4.0
>>> -9.0//2
-5.0
>>> 

Обратите внимание: если вы используете Python 2.1 или более раннюю версию, // работать не будет.

Операторы деления Python 3

$ python3.7
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 26 2018, 23:26:24) 
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 9/2
4.5
>>> -9/2
-4.
5 >>> 9.0/2 4.5 >>> -9.0/2 -4.5 >>> 9//2 4 >>> -9//2 -5 >>> 9.0//2 4.0 >>> -9.0//2 -5.0 >>>

В таблице ниже показаны результаты и пояснения для лучшего понимания.

9/244.5Для целых чисел Python 2 всегда возвращает int и возвращает минимальное значение. В то время как Python 3 возвращает значение с плавающей запятой.
-9/2-5-4,5Поскольку Python 2 возвращает значение пола, он возвращает -5.
9,0 / 24.54.5С числами с плавающей запятой и Python 2, и Python 3 возвращают значение с плавающей запятой, и их поведение одинаково.
-9,0 / 2-4,5-4,5То же, что и выше.
9 // 244Оператор разделения этажей работает одинаково как в Python 2, так и в Python 3.
-9 // 2-5-5
9.0 // 24.04.0
-9,0 // 2-5,0-5,0

 

Рейтинг

( 1 оценка, среднее 5 из 5 )

Васильев А.Н. / автор статьи

Помогаю в изучении Питона на примерах. Автор практических задач с детальным разбором их решений.

Комментарии0 Поделиться:

Загрузка …

Интерактивный учебник языка Python

Занятие 3. Вычисления

1. Целочисленная арифметика

Для целых чисел определены операции +, -, * и **. Операция деления / для целых чисел возвращает вещественное число (значение типа float). Также функция возведения в степень возвращает значение типа float, если показатель степени — отрицательное число.

Но есть и специальная операция целочисленного деления, выполняющегося с отбрасыванием дробной части, которая обозначается // (она соответствует операции div в Паскале). Она возвращает целое число: целую часть частного. Другая близкая ей операция − это операция взятия остатка от деления, обозначаемая % (она соответствует операции mod в Паскале). Например:

print(17 / 3)   # выведет 5.66666666667
print(17 // 3)  # выведет 5
print(17 % 3)   # выведет 2

2. Действительные числа

В этом разделе речь пойдет о действительных числах, имеющих тип float.

Обратите внимание, что если вы хотите считать с клавиатуры действительное число, то результат, возращаемый функцией input() необходимо преобразовывать к типу float:

x = float(input())
print(x)

Действительные (вещественные) числа представляются в виде чисел с десятичной точкой (а не запятой, как принято при записи десятичных дробей в русских текстах). Для записи очень больших или очень маленьких по модулю чисел используется так называемая запись «с плавающей точкой» (также называемая «научная» запись). В этом случае число представляется в виде некоторой десятичной дроби, называемой мантиссой, умноженной на целочисленную степень десяти (порядок). Например, расстояние от Земли до Солнца равно 1.496·10

11, а масса молекулы воды 2.99·10-23.

Числа с плавающей точкой в программах на языке Питон, а также при вводе и выводе записываются так: сначала пишется мантисса, затем пишется буква e, затем пишется порядок. Пробелы внутри этой записи не ставятся. Например, указанные выше константы можно записать в виде 1.496e11 и 2.99e-23. Перед самим числом также может стоять знак минус.

Напомним, что результатом операции деления / всегда является действительное число (float), в то время как результатом операции // является целое число (int).

Преобразование действительных чисел к целому производится с округлением в сторону нуля, то есть int(1.7) == 1, int(-1.7) == -1.

3. Библиотека math

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

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

import math

Например, пусть мы хотим округлять вещественные числа до ближайшего целого числа вверх. Соответствующая функция ceil от одного аргумента вызывается, например, так: math.ceil(x) (то есть явно указывается, что из модуля math используется функция ceil). Вместо числа x может быть любое число, переменная или выражение. Функция возращает значение, которое можно вывести на экран, присвоить другой переменной или использовать в выражении:

import math
x = math.
ceil(4.2) y = math.ceil(4.8) print(x) print(y)

Другой способ использовать функции из библиотеки math, при котором не нужно будет при каждом использовании функции из модуля math указывать название этого модуля, выглядит так:

from math import ceil
 
x = 7 / 2
y = ceil(x)
print(y)

или так:

from math import *
 
x = 7 / 2
y = ceil(x)
print(y)

Ниже приведен список основных функций модуля math. Более подробное описание этих функций можно найти на сайте с документацией языка Питон.

Некоторые из перечисленных функций (int, round, abs) являются стандартными и не требуют подключения модуля math для использования.

ФункцияОписание
Округление
int(x)Округляет число в сторону нуля. Это стандартная функция, для ее использования не нужно подключать модуль
math
.
round(x)Округляет число до ближайшего целого. Если дробная часть числа равна 0.5, то число округляется до ближайшего четного числа.
round(x, n)Округляет число x до n знаков после точки. Это стандартная функция, для ее использования не нужно подключать модуль math.
floor(x)Округляет число вниз («пол»), при этом floor(1.5) == 1, floor(-1.5) == -2
ceil(x)Округляет число вверх («потолок»), при этом ceil(1.5) == 2, ceil(-1.5) == -1
abs(x)Модуль (абсолютная величина). Это — стандартная функция.
Корни, логарифмы
sqrt(x)Квадратный корень. Использование: sqrt(x)
log(x)Натуральный логарифм. При вызове в виде log(x, b) возвращает логарифм по основанию b.
eОснование натуральных логарифмов e = 2,71828…
Тригонометрия
sin(x)Синус угла, задаваемого в радианах
cos(x)Косинус угла, задаваемого в радианах
tan(x)Тангенс угла, задаваемого в радианах
asin(x)Арксинус, возвращает значение в радианах
acos(x)Арккосинус, возвращает значение в радианах
atan(x)Арктангенс, возвращает значение в радианах
atan2(y, x)Полярный угол (в радианах) точки с координатами (x, y).
degrees(x)Преобразует угол, заданный в радианах, в градусы.
radians(x)Преобразует угол, заданный в градусах, в радианы.
piКонстанта π = 3.1415…

Ссылки на задачи доступны в меню слева. Эталонные решения теперь доступны на странице самой задачи.

Телеграм-канал создателя Питонтьютора 🌈

Что означает // в Python?

Что делает оператор Python // ? Чем он отличается от оператора /?

Оператор

/

Оператор / является оператором деления в Python.

Когда / используется между двумя числами, вы всегда получите точный (настолько точный, насколько Python может управлять) результат обратно:

 >>> 5 / 2
2,5
 

В отличие от некоторых языков программирования, / в Python не действует иначе при использовании между целыми числами; в Python 3 то есть. В Python 2 деление на два целых числа приведет к уменьшению до ближайшего целого числа:

 >>> 5 / 2 # Python 2
2
 

Но в Python 3 деление двух целых чисел всегда возвращает число с плавающей запятой с точным результатом:

 >>> 4 / 2
2.0
 

Оператор

// между целыми числами

// 9Оператор 0004 — это оператор деления пола в Python. Когда // используется между двумя целыми числами, вы всегда получите целое число:

 >>> 5 // 2
2
 

Оператор // обеспечивает деление при округлении результата до ближайшего целого числа. Это часто называют целочисленным делением или делением пола .

При использовании // с числом с плавающей запятой вы получите обратно число с плавающей запятой:

 >>> 5.0 // 2
2.0
 

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

Когда следует использовать

// в Python?

Если вы когда-нибудь видели такой код:

 >>> n = 5
>>> целое(n / 2)
2
 

Тогда вы, вероятно, видели возможность использовать оператор // . Если вы делите, а затем сразу же конвертируете результат в целое число, вы, вероятно, могли бы использовать 9Вместо оператора 0003 // .

В этой функции split_in_half мы используем функцию int , чтобы убедиться, что значение mid_point является целым числом:

 def split_in_half(sequence):
    """Вернуть две половины заданной последовательности (список, строка и т.д.)"""
    mid_point = int (len (последовательность) / 2)
    возвращаемая последовательность[:mid_point], последовательность[mid_point:]
 

Оба числа, которые мы делим, являются целыми числами, поэтому мы могли бы использовать // , чтобы получить целочисленный результат:

 по определению split_in_half (последовательность):
    """Вернуть две половины заданной последовательности (список, строка и т. д.)"""
    mid_point = len(последовательность) // 2
    возвращаемая последовательность[:mid_point], последовательность[mid_point:]
 

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

Обратите внимание, что

// всегда округляется в меньшую сторону

Прежде чем вы замените все варианты использования int(a / b) в вашем коде с a // b , вы должны заметить, что эти два действия действуют по-разному, когда результатом деления является отрицательное число:

Допустим, мы делим и получаем результат -2,5 :

 >> > а = -5
>>> б = 2
>>> а/2
-2,5
 

При использовании / и int мы получим -2 , но при делении на // мы получим -3 вместо:

 >>> int(a / 2 )
-2
>>> а // 2
-3
 

Оператор // всегда округляет в меньшую сторону. Он действует не столько как встроенная функция int , сколько как math.floor :

 >>> from math import floor
>>> этаж(а/2)
-3
>>> а // 2
-3
 

Также помните, что a // b возвращает число с плавающей запятой, когда либо a , либо b являются числами с плавающей запятой.

 >>> а = 52,0
>>> б = 4
>>> а // б
13,0
 

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

Использование

divmod вместо

Что делать, если вам нужно целочисленное деление (с // ) и остаток от этого деления (с % ):

 >>> duration = 500
>>> минуты = продолжительность // 60
>>> секунды = продолжительность % 60
>>> print(f"{минуты}:{секунды}")
8:20
 

Вместо // и % отдельно, вы можете использовать функцию divmod , чтобы получить оба результата одновременно:

 >>> duration = 500
>>> минуты, секунды = divmod(длительность, 60)
>>> print(f"{минуты}:{секунды}")
8:20
 

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

Иногда divmod может сделать код значительно более читаемым. Например, здесь мы используем // и % , чтобы получить часы, минуты и секунды:

 >>> duration = 9907
>>> часы = продолжительность // (60 * 60)
>>> минуты = (длительность // 60) % 60
>>> секунды = продолжительность % 60
>>> print(f"{часы}:{минуты:02d}:{секунды:02d}")
2:46:07
 

Но вместо этого мы могли бы дважды использовать divmod :

 >>> duration = 9907
>>> минуты, секунды = divmod(длительность, 60)
>>> часы, минуты = divmod(минуты, 60)
>>> print(f"{часы}:{минуты:02d}:{секунды:02d}")
2:46:07
 

Я считаю, что подход divmod намного понятнее, чем альтернативное использование // и % . Если вам нужно как частное (если использовать математический термин), так и остаток от деления, рассмотрите возможность использования divmod .

Примечание : если вам интересно, :02d 9Синтаксис 0004 выше, см. заполнение нулями в f-строках.

Используйте

// для целочисленного деления

Для большинства применений деления в Python вы, вероятно, будете использовать / , потому что часто желательны точные ответы:

 >>> amount = 67
>>> групп = 9
>>> per_partion = количество/группы
>>> per_partion
7.444444444444445
 

Но в редких случаях, когда вам нужно деление пола (также известное как целочисленное деление ), вам понадобится // оператор.

 >>> сумма = 67
>>> групп = 9
>>> Minimum_per_group = количество // групп
>>> минимум_на_группу
7
 

Если вам нужен остаток % и целочисленное деление // , также помните о функции Python divmod .

 >>> продолжительность = 784
>>> минуты, секунды = divmod(длительность, 60)
>>> print(f"{минуты}м{секунды}с")
13м4с
 

Целочисленное деление — Справка по Python

Думара (ДУМИСАНИ СИБАНДА) 1

Каков результат этого кода: print(6 // 0.4)
Я думал, что ответ 15,0, но я получаю 14,0. Буду признателен за любое объяснение этого ответа.

PythonCHB (Кристофер Х.Баркер, доктор философии) 2

Это действительно хороший вопрос!

Я думаю что происходит, когда 0,4 преобразуется в двоичное число с плавающей запятой, вы получаете значение немного больше, чем 0,4:

 В [40]: f"{0.4:.40f}"
Выход[40]: '0,4000000000000000222044604925031308084726'
 

Таким образом, 6/0,4 немного меньше, чем 15,0, и, таким образом, усекается до 14,0

Однако (и теперь я не в курсе FP) – когда вы на самом деле вычисляете 6/0,4, вы получаете 15,0 (что точно представимо в двоичном формате), насколько я могу судить:

 В [43]: f"{6 / 0. 4:.60f}"
Выход[43]: '15.00000000000000000000000000000000000000000000000000000000000000'
 

Так что я не понимаю, почему округление не происходит так же, как перед усечением.

Я уверен, что кто-то, кто разбирается в FP лучше меня, сможет объяснить…

-CHB

2 лайка

роб42 (Роб) 3

Если мы скажем x = 6 и y = 0,4

Тогда x / y будет 15 , но // называется делением пола, так что вы получите 9 0003 14.0 , а что ты не вижу — это остаток, который в соотношении меньше «0,4». Вы можете увидеть как частное, так и остаток, используя функцию с именем divmod() :

divmod(x, y) = (14.0, 0.39999999999999997)

вернуть количество дней и часов для любого заданного количества часов:

 день = 24 # количество часов в сутках
hours = 172 # количество часов
дни, часы = divmod(часы, день)
print(f"{days} дней, {hrs} часов")
печать(часы/день)
печать (часы // день)
 

Вывод:

 7 дней, 4 часа
7. 166666666666667
7
 

Редактирование выполнено для незначительного исправления кода.

1 Нравится

steven.daprano (Стивен Д’Апрано) 4

В Python нет «целочисленного деления». У нас есть деление пола , которое делает деление, сохраняя пол результата.

Если вы не знаете, что такое пол и потолок в математике:

mathsisfun.com

Функции пола и потолка

Математика, объясненная простым языком, а также головоломки, игры, викторины, рабочие листы и форум. Для детей K-12, учителей и родителей.

Деление этажей с помощью чисел с плавающей запятой странно, гораздо проще понять это только с целыми аргументами. 60//4 ровно 15, как мы и ожидали.

Как обычно, странность заключается в том, что числа с плавающей запятой представляют собой двоичные числа, а не десятичные. Число с плавающей запятой 0,4 — это не , а точно , равное десятичному числу 0,4, на самом деле оно немного больше:

 >>> "%.50f" % 0,4
'0,40000000000000002220446049250313080847263336181641'
 

Итак, на самом деле мы делим на что-то чуть большее, чем десятичное число 0,4. И это имеет значение.

  • В действительных числах 6 разделить на ровно 0,4 дает ровно 15.

  • Но что-то немного большее, чем 0,4, превращается всего в 14 раз в 6, плюс напоминание.

Мы можем вычислить остаток:

 >>> 6 % 0,4
0,3999999999999997
 

Посмотрите на остаток: это почти равно 0,4, на самом деле это следующий float просто под 0,4 :

 >>> math.nextafter(0,4, 0,0)
0,39999999999999997
 

С истинным делением, 6/0,4 , мы получаем:

  • 6 разделить на что-то чуть больше 0,4 дает что-то чуть меньше 15;
  • , но в этом случае деление округляется точно до 15,0 .

Если вы думаете, что все это ужасно сложно, вы правы.

1 Нравится

PythonCHB (Кристофер Х.Баркер, доктор философии) 5

Что меня еще здесь смущает, так это:

 В [73]: f"{0.4:.40f}"
Выход[73]: '0,4000000000000000222044604925031308084726'
 

Итак, двоичное представление литерала 0,4 немного больше, чем реальное число 0,4 — понятно. Таким образом, ожидается, что 6,0/0,4 будет немного меньше, чем 15,0:

 В [75]: 6,0/0,4
Аут[75]: 15,0
 

, но немного меньше (как указано, настолько близко, насколько это возможно для 64-битного числа с плавающей запятой), будет отображаться python как округленное 15.0.

Однако:

 В [77]: f"{6.0/0.4:.40f}"
Выход[77]: '15.00000000000000000000000000000000000000000'
 

, так что на самом деле это 15,0, и точно так же, как то, что создает буквальное 15,0:

 В [82]: (6,0 / 0,4) == 15,0
Выход[82]: Верно
 

IIUC, малые целые числа точно представлены в FP — поэтому кажется, что когда мы делаем деление, мы получаем ровно 15. Таким образом, кажется, что происходит какое-то округление, когда мы делаем простое деление, которое не выполняется до пола берется по этажам – и это меня смущает.

ПРИМЕЧАНИЕ: пример с днями, часами напомнил мне о коде, который я написал много лет назад, который преобразовывал широту и долготу из десятичных (плавающих) значений в градусы, минуты, секунды. Простой способ с использованием % и т.п. для определенных значений приведет к таким вещам, как:

9 градусов, 23 минуты 60 секунд
, когда должно быть 24 минуты, ноль секунд.

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

Я обнаружил это только потому, что случайно выбрал число в тесте, который вызвал проблему.

тим.один (Тим Питерс) 6

Кристофер Х. Баркер, доктор философии:

IIUC, малые целые числа точно представлены в FP — поэтому кажется, что когда мы делаем деление, мы получаем ровно 15. Таким образом, кажется, что происходит какое-то округление, когда мы делаем простое деление, которое не выполняется до того, как пол взято по этажам — и это меня смутило.

Да, целые числа с абсолютным значением <= 2**53 точно представлены с двойной точностью IEEE-754 (тип float CPython).

6,0 / 0,4 равно 15,0, потому что аппаратное деление округляет его до 15. 15,0 — это ближайшее представимое значение к бесконечно точному результату.

Но деление этажей Python на это не обращает внимания — оно округляет до ближайшего целого числа в сторону минус бесконечности. Аппаратное обеспечение не делает этого — CPython усердно работает, чтобы дать вам истинное преимущество. С бесконечной точностью 6, деленное на приближение с плавающей запятой 0,4, немного меньше 15,0, поэтому пол дает 14,0.

Прекрасный модуль mpmath позволяет с легкостью исследовать подобные вещи, выполняя двоичные арифметические операции в стиле IEEE с настраиваемой пользователем точностью:

 >>> import mpmath
>>> печать(mpmath.mp)
Настройки мпмат:
  mp.prec = 53 [по умолчанию: 53] # по умолчанию 53 бита, то же, что и 754 double
  mp.dps = 15 [по умолчанию: 15]
  mp.trap_complex = Ложь [по умолчанию: Ложь]
>>> mpmath.mp.prec = 80 # увеличить точность до 80 бит
>>> печать(mpmath.mp)
Настройки мпмат:
  mp.prec = 80 [по умолчанию: 53] # мы изменили это
  mp.dps = 23 [по умолчанию: 15]
  mp.trap_complex = Ложь [по умолчанию: Ложь]
>>> mpmath.mpf(0.4) # рассматриваемое число
mpf('0.40000000000000002220446049')
>>> 6.0 / mpmath.mpf(0.4) # показывает, что бесконечно точный результат < 15
мпф('14.999999999999999167332732')
>>> mpmath.mp.prec = 53 # но это округляет до 15 при 53-битной точности
>>> 6. 0 / mpmath.mpf(0.4)
м/с('15.0')
 

1 Нравится

steven.daprano (Стивен Д’Апрано) 7

Верно, маленькие целые числа точны в 64-битных числах с плавающей запятой, но причина не в этом 6.0/0.4 дает ровно 15.0.

Согласно математике IEEE-754 расчеты должны быть правильно округлены. Любой, кто достаточно взрослый, чтобы помнить компьютерную арифметику до IEEE-754, вероятно, может рассказать вам много ужасных историй, таких как

  • x != y, но x — y = 0,0
  • х == у, но х/у != 1,0

Эти мерзости невозможны в математике IEEE-754. Но я отвлекся.

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

Когда мы вычисляем 6,0/0,4 , мы фактически вычисляем

 6,0/(0,4 + d)
 

для некоторого крошечного значения d, которое работает как 15.0 - e для некоторого другого крошечного значения e. В этом конкретном случае так получилось, что разница между истинным значением 15,0 и вычисленным значением 15,0 - e настолько мала, что при округлении трех защитных цифр результатом оказывается истинное значение 15,0. .

Но это не всегда происходит с каждым делением:

 (6*7)/(0,4*7) # Математически точный результат = 15,0
--> но возвращает 14.9999999999999998
 

Семантика IEEE-754 гарантирует, что при делении двух двоичных чисел результат всегда правильно округляется до двоичного . Это не обязательно означает, что результат выглядит правильно в десятичном виде, но иногда нам везет:

  • точное значение 6.0
  • при делении на неточное значение 0,4
  • дает значение чуть меньше 15,0 при использовании 3 дополнительных битов
  • , который при округлении до 64 бит в конечном итоге будет точным значением 15,0
  • и многие радуются.

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

PythonCHB (Кристофер Х.Баркер, доктор философии) 8

Спасибо, Тим, это объясняет, хотя, на мой наивный взгляд, деление пола в Python здесь не совсем правильно (или не лучше) — результаты были бы менее удивительными, если не более правильными, если бы:

a // b дал тот же результат, что и math.floor( a / b) , но это не так:

 В [137]: 6 // 0.4 == math.floor(6 / 0.4 )
Выход[137]: Ложь
 

Также, с моей наивной точки зрения, я удивлен // на самом деле не реализован таким образом

Насколько я мог сказать при быстром поиске, IEEE 754 не определяет «этажное деление» — интересно, что он указал бы, если бы это было так?

ПРИМЕЧАНИЕ: до того, как в Python было определено деление этажей, я полагаю, люди сделали бы math. floor(a / b) — так ввели несовместимость.

На самом деле, если вы используете целые числа слишком большие, чтобы их можно было точно представить числами с плавающей запятой, то целочисленное деление ОТЛИЧАЕТСЯ от напольного деления, что кажется мне неоптимальным:

 В [148]: a
Out[148]: 60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
В [149]: б
Out[149]: 4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
В [150]: а/б
Аут[150]: 15,0
В [151]: float(a) // float(b)
Аут[151]: 14,0
 

Конечно, для практических целей вряд ли подойдет, но все же.

Росуав (Крис Анджелико) 9

Кристофер Х. Баркер, доктор философии:

Спасибо, Тим, это объясняет, хотя, на мой наивный взгляд, деление пола в Python здесь не работает правильно (или не лучше) — результаты были бы менее удивительными, если не более правильными, если бы:

a // b дал тот же результат, что и math. floor( a / b) , что не так:

 В [137]: 6 // 0,4 == math.floor(6 / 0,4)
Выход[137]: Ложь
 

Также, на мой наивный взгляд, я удивлен // на самом деле не реализован таким образом

Лучшей корреляцией будет то, что a // b должно быть таким же, как divmod(a, b)[0] , что a % b должно быть таким же, как divmod(a, b)[1 ] , а затем этот divmod определяется с помощью этого правила:

 q, r = divmod(a, b)
утверждать q * b + r == a
 

, как указано в строке документации divmod. Насколько я знаю, это должно быть верно для всех числовых типов. (К сожалению, я не могу использовать divmod со строками, даже если я создаю подкласс str , так что x // y <=> x.split(y) — он все еще возражает против объектов, которые я ему подаю. Ооооо.)

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

тим.один (Тим Питерс) 10

Кристофер Х. Баркер, доктор философии:

Насколько я понял при быстром поиске, IEEE 754 не определяет «этажное деление» — интересно, что бы он указал, если бы дал?

Полностью совместимая реализация 754 должна поддерживать 4 различных режима округления, определенных этим стандартом. Округление «до минус бесконечности» — это то, что мы здесь называем «полом». Его округление «до плюс бесконечности» — это то, что мы называем «потолком». Но ядро ​​​​Python не поддерживает какой-либо способ получить настройку режима округления вашего оборудования. Если бы это было так, и вы запросили округление «до минус бесконечности», ваше аппаратное подразделение также вернуло бы результат меньше 15,0 для 6 / 0,4 .

 >>> импорт mpmath
>>> mpmath.fdiv(6.0, 0.4)
м/с('15.0')
>>> mpmath.fdiv(6.0, 0.4, округление='пол')
мпф('14.999999999999998')
 

По сути, все 754 операции определены для возврата бесконечно точного результата с одним округлением в конце. Нет никаких аргументов в пользу «правильного» результата для 6 / 0,4 . Он точно определен для каждого режима округления.

Более плодотворным вопросом было бы задаться вопросом, почему Python вообще поддерживает «этажное деление» для чисел с плавающей запятой. Это очень полезно для целых чисел, но у целых чисел есть много приятных математических свойств, которых нет у чисел с плавающей запятой. В том же ключе близкое определение для целого числа % результатов тоже не совсем то, что нужно float.

Так и есть. Очень многие языки соблазнены наблюдением, что математически целые числа являются подмножеством действительных чисел. Вот откуда берется желаемое за действительное с «числовой башней». Но машинные поплавки очень далеки от «настоящих». Машинные числа с фиксированной точностью на самом деле являются странно неуклюжим конечным подмножеством рациональных чисел, дополненным странными «бесконечностью» и особыми случаями «NaN».

Кристофер Х. Баркер, доктор философии:

ПРИМЕЧАНИЕ: до того, как разделение этажей было определено в Python,

Подразделение

Floor было частью Python с первого дня, поэтому «до» не существует. Однако для поплавков, чтобы добраться до него, вам нужно было сначала написать его как divmod(x, y)[0] .

Кристофер Х. Баркер, доктор философии:

Я полагаю, что люди сделали бы math.floor(a / b) — поэтому была введена несовместимость.

В значении этого фрагмента ничего не изменилось. / имеет , всегда означало «истинное деление» для чисел с плавающей запятой. Хотя я немного вру: math.floor() до недавнего времени возвращал число с плавающей запятой вместо int, отражая то, что делает C libm floor() . Изменение этого тоже не было, ИМО, хорошей идеей.

Стивен Дапрано (Стивен Д’Апрано) 11

Думаю, вы удивлены, потому что не можете пройти мимо того факта, что буквальное число 0.4 выглядит как точная десятичная дробь 4 от 10, поэтому вы думаете, что 6/0.4 точно правильно, а 6//4 имеет ошибку округления.

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

Вместо буквального числа 0,4 , давайте предположим, что ваш делитель был результатом какого-то длинного, сложного вычисления, где вы не ожидаете того, что в итоге получится ровно одна пятнадцатая от 6:

Вот пример такого сложного вычисления, которое полностью не придумано

 x = 7205759403792794,0 * 5,551115123125783e-17
 

Если мы вычислим 6//x без предварительной проверки значения x и получим 14,0, мы ничуть не удивимся. Нам нужно было получить какое-то целое число, и 14,0 не более и не менее удивительно, чем любое другое.

Если мы теперь проверим значение x до полной точности , мы увидим что-то вроде 0,40000…7263336181640625, и нас вряд ли удивит, что число, которое мы вычислили, является «странным десятичным числом», почти все числа «странные» в ощущение наличия набора цифр без очевидной закономерности.

Единственная странность в этом x состоит в том, что в середине числа есть несколько нулей подряд, но это не , а удивительно. Во многих числах есть куча нулей.

Итак, теперь давайте возьмем это «странное десятичное число» x и разделим его на 6. Было бы совпадением, если бы получилось разделить точно на на 6 и получить в результате целое число, верно?

На самом деле, если мы посмотрим на длинный хвост цифр в точном десятичном представлении … 7263336181640625, это будет удивительное число , если оно делится точно, мы должны получить что-то вроде 14,9999999…987 или 15,000000…132 или что-то в этом роде.

И еще, как по волшебству, ошибка округления в 6/x исчезает и остается ровно 15.0.

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

PythonCHB (Кристофер Х.Баркер, доктор философии) 12

Стивен Д’Апрано:

Я думаю, вы удивлены, потому что не можете пройти мимо того факта, что буквальное 0,4 выглядит как точная десятичная дробь 4 от 10, и поэтому вы думаете, что 6/0,4 точно правильно, а 6//4 имеет ошибку округления.

Ну, нет, я не — я думал, что ясно дал понять, что был удивлен, потому что я ожидал, что «этажное деление» будет тем же, что взять слово после деления — т. е. этаж (а / б) — и это не так, что Тим довольно хорошо объяснил.

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

Если на то пошло, я не раз удивлялся тому, что a_float // a_float возвращает число с плавающей запятой — разве оно не всегда должно быть целым числом?

если floor(a_float) возвращает целое число, то почему не деление на пол?

(Тим утверждает, что floor() не должны возвращаться и int — что по крайней мере будет согласовано)

Я особенно удивлен, потому что in_int // an_int действительно возвращает int, и все это было создано, чтобы прояснить неожиданности, которые мы получали, когда результат операции зависел от типа (а не от значения) операторов.

Оставить комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *