Каково поведение целочисленного деления?


211

Например,

int result;

result = 125/100;

или

result = 43/100;

Результатом всегда будет пол дивизиона? Что такое определенное поведение?


5
Резюме: подписано целочисленное деление обрезает к нулю . Для неотрицательных результатов это то же самое, что и этаж (округление в сторону -Infinity). (Остерегайтесь того, что C89 не гарантирует этого, см. Ответы.)
Питер Кордес

6
Все продолжают говорить «усекать до нуля», «потолок» или «пол», как в коде, и обдумывать, какую технику использовать. Если бы код мог говорить, он сказал бы"I just throw the dam fraction part in the trash and move on with life"
Тимоти Л.Дж. Стюарт

3
@ TimothyL.J.Stewart «Код» принимает обдуманное решение. Согласно спецификации, целочисленное деление подразумевается как T (runcation)-деление. Из-за этого оператор по модулю / остатку вводится иначе, чем если бы он был на другом языке, скажем, Python или Ruby. Смотрите это для списка различных способов сделать язык оператора по модулю и этой бумаги , что списки по крайней мере пять из распространенных способов языков программирований решают сделать DIV / по модулю.
13steinj

1
@ 13steinj Я говорю в разговорной речи за комментарии, которые он превращал в «это усечено до нуля ... нет, это пол ... нет, если его отрицательный потолок ...» иногда технические детали не распространяются в будущее с человеческой памятью как мы хотим, но зная интуитивно, что «часть дроби выброшена», вы можете получить технические моменты. Технические детали - это тяжелое бремя, но интуиция легкая и освежающая, как ветер, я перенесу их повсюду и, когда необходимо, я буду знать, с чего начать. Как та бумага, которую вы связали, спасибо.
Тимоти LJ Стюарт

Я ответил здесь с акцентом на евклидово деление (взаимодействие между целочисленным делением и оператором модуля).
Пикауд Винсент

Ответы:


182

Результатом всегда будет пол дивизиона? Что такое определенное поведение?

Да, целочисленное отношение двух операндов.

6.5.5 Мультипликативные операторы

6 Когда целые числа делятся, результатом оператора / является алгебраический фактор с любой отброшенной дробной частью. 88) Если частное a / b представимо, выражение (a / b) * b + a% b должно быть равно a.

и соответствующая сноска:

88) Это часто называют усечением до нуля.

Конечно, следует отметить два момента:

3 Обычные арифметические преобразования выполняются над операндами.

и:

5 Результатом оператора / является частное от деления первого операнда на второй; результат оператора% - остаток. В обеих операциях, если значение второго операнда равно нулю, поведение не определено.

[Примечание: Акцент мой]


26
... если, конечно, вы не делите отрицательное число на положительное (или vv), в этом случае это будет потолок.
Будет ли

74
Это не пол и не потолок, это усечение дробной части, концептуально другое!
lornova

38
@ Будет: Нет. Это определяется как усечение до нуля. Называя это как-нибудь еще, только добавит путаницы, поэтому, пожалуйста, воздержитесь от этого.
Мартин Йорк,

44
По крайней мере, с математической точки зрения, усечение до нуля эквивалентно «если> 0, то другой потолок». Я думаю, что просто называть это усечением проще, чем называть это пол / потолок, но любой из них действителен. Несмотря на это, точка зрения Уилла А действительна: ответ Диркгентли частично неверен, поскольку он заявил, что ОП прав в том, что результатом является пол подразделения.
Брайан

9
@Philip Potter: Я не думаю, что это было определено в C89, и это не в стандарте C ++ 1998 года. В них, конечно, (a / b) * b + a % b == aдолжны были быть выполнены, и абсолютное значение a % bдолжно было быть меньше a, но было ли a % bотрицательным для отрицательного aили bне было указано.
Дэвид Торнли

41

Диркгентли дает отличное описание целочисленного деления в C99, но вы также должны знать, что в C89 целочисленное деление с отрицательным операндом имеет направление, определяемое реализацией.

Из проекта ANSI C (3.3.5):

Если любой из операндов отрицателен, то, является ли результат оператора / наибольшим целым числом, меньшим, чем алгебраическое частное, или наименьшим целым числом, большим, чем алгебраическое частное, определяется реализацией, как и знак результата оператора%. Если частное a / b представимо, выражение (a / b) * b + a% b должно быть равно a.

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

Это забавный факт, что C99 выбрал усечение до нуля, потому что именно так сделал это ФОРТРАН. Смотрите это сообщение на comp.std.c.


2
И в абзаце 5 предисловия C99 N1256 упоминается reliable integer divisionкак новая языковая функция. Удивительно *-*.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

Усечение - это поведение наиболее распространенного аппаратного обеспечения процессора (например, x86), поэтому было бы безумно делать другой выбор. Сначала был IDK, семантика Fortran или поведение аппаратного обеспечения, но это не совпадение, что они одинаковы.
Питер Кордес

2
@PeterCordes: Наиболее распространенное аппаратное обеспечение ЦП может выполнять деление по этажам по большинству констант быстрее, чем деление по усечению. ИМХО, для Стандарта было бы лучше сказать, что expr1 / expr2и expr1 % expr2должно быть согласовано друг с другом, когда оба экземпляра expr1объединяют одни и те же объекты одинаково, и аналогично expr2, но выбор усечения по сравнению с разделением по этажам в противном случае не указан. Это позволило бы более эффективно генерировать код, не нарушая при этом большую совместимость (и реализации могли бы задокументировать конкретное поведение, если склонялись)
суперкат

23

Там, где результат отрицательный, C усекается до 0, а не до пола - я узнал из этого прочтения о том, почему целочисленное деление Python всегда здесь: почему целочисленное деление этажей Python


3
Я согласен с комментарием, задающимся вопросом, полезно ли когда-либо отрицательное отрицательное значение? В связи с этим я хотел бы знать, полезно ли когда-либо требуемое арифметически-некорректное поведение в некоторых случаях «unsignedvar> signaturevar»? Я могу понять причину, по которой не требуется всегда правильного поведения; Я не вижу смысла требовать неправильного поведения.
суперкат

8
+1 за отличную справку о том, почему настил является правильным поведением для целочисленного деления (вопреки определению С, которое не работает и почти никогда не используется).
R .. GitHub ОСТАНОВИТЬСЯ, ПОМОГАЯ ЛЬДУ

@supercat Рассмотрим:, filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factorповторяется с изменением значений value. Это делает хорошее целочисленное приближение к фильтру нижних частот первого порядка с постоянной времени k... но это только симметрично, если деление усекается и carryполучает отрицательные значения. Время от времени пригодятся оба способа разделения.
Хоббс

1
@hobbs: я не думаю, что приведенный выше код будет вести себя чисто, когда сигналы пересекают ноль. Если divявляется операцией деления по полу и factorявляется нечетным, то filtered += (filter+(factor div 2)) div factorприведет к чистому и симметричному поведению для всех значений до INT_MAX-(factor div 2).
суперкат

@supercat это работает, хотя; этот код только слегка искажен от того, что я некоторое время выполнял в контроллере атомных часов.
Хоббс

21

Да, результат всегда обрезается до нуля. Он округлится до наименьшего абсолютного значения.

-5 / 2 = -2
 5 / 2 =  2

Для неподписанных и неотрицательных значений со знаком это то же самое, что и floor (округление в сторону -Infinity).


43
Усечение, а не пол.
Ден04

9
@ dan04: да, пол будет действительным только для натуральных чисел :)
Леонид

13

Результатом всегда будет пол дивизиона?

Нет. Результат варьируется, но изменение происходит только для отрицательных значений.

Что такое определенное поведение?

Чтобы было яснее, пол округляется в сторону отрицательной бесконечности, а целочисленное деление округляется до нуля (усекается)

Для положительных значений они одинаковы

int integerDivisionResultPositive= 125/100;//= 1
double flooringResultPositive= floor(125.0/100.0);//=1.0

Для отрицательного значения это отличается

int integerDivisionResultNegative= -125/100;//=-1
double flooringResultNegative= floor(-125.0/100.0);//=-2.0

0

Я знаю, что люди ответили на ваш вопрос, но с точки зрения непрофессионала:

5 / 2 = 2 // поскольку 5 и 2 являются целыми числами, а деление целых чисел всегда усекает десятичные дроби

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 // здесь либо 5, либо 2, либо оба имеют десятичную дробь, поэтому полученное вами значение будет в десятичной дроби.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.