У чому причина різниці між цілим поділом та перетворенням на int в python?


52

Нещодавно я помітив, що int()круглі плавають у напрямку до 0, тоді як ціле ділення округляє поплавок до його підлоги.

наприклад:

-7 // 2 = -4
int(-7/2) = -3

Я прочитав документацію, яка вказує:

клас int (x, база = 10)

Поверніть цілий об'єкт, побудований з числа або рядка x, або поверніть 0, якщо аргументи не вказані. Якщо x число, поверніть x. int (). Для чисел з плаваючою комою це скорочення до нуля.

і:

поділ підлоги

Математичний поділ, який округляється до найближчого цілого числа. Оператор поділу поверху //. Наприклад, вираз 11 // 4 оцінює до 2 на відміну від 2,75, повернутого поплавковим істинним поділом. Зауважимо, що (-11) // 4 дорівнює -3, тому що це -2,75 закруглені вниз. Див. PEP 238.

Але мені здається нелогічним, що дві подібні операції (поплавковий поділ на ціле число) повинні повертати різні результати.

Чи є мотивація відмінностей між функціями?

Дякую.


Відповідне посилання: python-history.blogspot.com/2010/08/…
dan04

Відповіді:


61

Послідовність.

Вам потрібно буде дотримуватися деяких дуже базових і, здавалося б, неактуальних пояснень, щоб зрозуміти це.

У школі ви вивчили поділ із залишками. І ви зробили розрахунки так:

8 ÷ 4 = 2 R 0
7 ÷ 4 = 1 R 3
6 ÷ 4 = 1 R 2
5 ÷ 4 = 1 R 1
4 ÷ 4 = 1 R 0
3 ÷ 4 = 0 R 3
2 ÷ 4 = 0 R 2
1 ÷ 4 = 0 R 1
0 ÷ 4 = 0 R 0
        ^------ This is the result of x // 4
            ^-- This is the result of x % 4 (modulo)

Пізніше ви дізналися поділи на реальні числа:

8 ÷ 4 = 2.0
7 ÷ 4 = 1.75
6 ÷ 4 = 1.5
5 ÷ 4 = 1.25
4 ÷ 4 = 1.0
3 ÷ 4 = 0.75
2 ÷ 4 = 0.5
1 ÷ 4 = 0.25
0 ÷ 4 = 0.0
        ^--- Note that the number in front of the . is int(x/4)

До цього моменту ви можете в це повірити x // 4і int(x/4)завжди давати однаковий результат. Це ваше теперішнє розуміння ситуації.

Однак подивіться, що відбувається в цілому поділі: число позаду R циклів від 3, 2, 1 до 0, а потім перезапустить: 3, 2, 1, 0. Число перед R зменшується на кожному четвертому кроці.

Отже, як це буде тривати далі?

 8 ÷ 4 =  2 R 0
 7 ÷ 4 =  1 R 3
 6 ÷ 4 =  1 R 2
 5 ÷ 4 =  1 R 1
 4 ÷ 4 =  1 R 0
 3 ÷ 4 =  0 R 3
 2 ÷ 4 =  0 R 2
 1 ÷ 4 =  0 R 1
 0 ÷ 4 =  0 R 0
-1 ÷ 4 = -1 R 3
         ^------ We have to decrease now, because we already have 0 four times
              ^-- We have to restart the cycle at 3

У той же час, ділення реального числа дає нам:

-1 ÷ 4 = -0.25
          ^----- There is still a 0 in front of the .

Ось чому -1 // 4дає -1, але int(-1/4)дає 0.

Чи є мотивація відмінностей між функціями?

Ну, вони служать різним цілям: //є частиною цілого розрахунку з залишками і int()дає вам частину перед .операцією з реальним числом.

Ви вирішуєте, що ви хочете обчислити, тоді ви вирішите, якого оператора використовувати в Python, щоб отримати правильний результат.

Хороше питання. Продовжуйте вчитися.


11
На практиці це дозволяє зробити хитрість: якщо у вас -1 солодощів, і ви їх роздасте чотирьом друзям, тоді залишиться 3 солодощі. Чудово, чи не так? Потрібно лише з’ясувати, як володіти -1 солодощами.
Томас Веллер

1
Це створює певну послідовність, наскільки я розумію мотивацію додавання //оператора в python 3, щоб уникнути примусового використання int (float). Якщо це не так, коли я повинен вирішити використовувати, int()і коли я повинен реалізувати використання//
IsaacDj

1
Гаразд, тоді це просто неправильне припущення. Це нічого поганого, якщо ви перевіряєте свої припущення щодо правильності, що, мабуть, не спрацьовує у 50% випадків (принаймні, це для мене). У відповідь я додав кілька слів про це.
Томас Веллер

2
@IsaacDj Ви можете прочитати це для розповіді за оператором "підрозділ підлоги".
bruno desthuilliers

1
@EricLippert: Я не думаю, що це химерно. Ми не можемо вважати, що операція з втратою забезпечує той же результат, що і для точної операції. Розмова в коді: Math.Floor(3.23) != -Math.Floor(-3.23)З тієї ж причини -((-x)//y)не потрібно дорівнювати x//y.
Томас Веллер

4

Я б сказав, що очікується, що очікується, що ці 2 операції мають бути інтуїтивно схожими, очікується, оскільки в позитивних числах вони поводяться однаково. Але якщо поглянути на їхнє походження (одне походить з математики, а інше - з інформатики), то має більше сенсу їхня інша поведінка.

Ви можете подивитися за поняттями:

  • Розділення підлоги, також функція підлоги, застосовувана до математичного поділу
  • Перетворення типів / кастинг типів

===================================================== ================

I) Розділення підлоги, також функція підлоги, застосована до математичного поділу

Функція підлоги - це дуже усталене поняття в математиці.

З сайту mathworld.wolfram :

Функція підлоги | _ x_ |, яка також називається найбільшою цілою функцією або цілим числом (Spanier and Oldham 1987), дає найбільше ціле число, менше або рівне x. Ім'я та символ функції підлоги були введені К. Е. Іверсоном (Graham et al., 1994)

Отже поділ підлоги - це не що інше, як функція підлоги, застосована до математичного поділу. Поведінка дуже чітка, "математично точна".

II) Перетворення типу / лиття типу

З Вікіпедії :

В інформатиці перетворення типів, кастинг типів, примус типу та жонглювання типу - це різні способи зміни виразу з одного типу даних на інший.

У більшості мов програмування форма лиття з цілим числом застосовується за допомогою правила округлення (тому існує умовність):

  • Закруглення до 0 - спрямоване округлення до нуля (також відоме як усічення)

Правило округлення згідно IEEE 754 .


Інакше кажучи, причина різниці між цілим поділом і перетворенням flot в int в python є математичною, ось деякі думки від Гвідо ван Россума (я думаю, я не повинен його вводити: D) (з блог Історія Python, стаття "Чому підрозділ цілої частини Python" )

Це турбує деяких людей, але є хороша математична причина. Операція ділення на ціле число (//) та його побратими, модульна операція (%), йдуть разом і задовольняють хороший математичний взаємозв'язок (усі змінні - цілі числа):

a / b = q з залишком r

такий як

b * q + r = a і 0 <= r <b

(якщо a і b> = 0).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.