В Python, что является хорошим способом округления до нуля при целочисленном делении?

1/2

дает

0

как это должно. Однако,

-1/2

дает

-1

, но я хочу, чтобы оно округлялось до 0 (т. е. я хочу, чтобы -1/2 было равно 0), независимо от того, положительное оно или отрицательное. Как лучше всего это сделать?


person blacktrance    schedule 12.11.2013    source источник
comment
int(1./2) должно работать.   -  person karthikr    schedule 12.11.2013
comment
Вопрос в теме понятен, но примеры вводят в заблуждение. 1 / 2 и -1 / 2 дают соответственно 0,5 и -0,5 в Python, а не 0. Более того, функция round() дает то, что запрашивается в примерах: round(1 / 2) = round( -1 / 2 ) = 0, потому что Python округляет до четного целого числа, когда у него есть выбор между двумя одинаково близкими целыми числами.   -  person Dominic108    schedule 20.03.2021
comment
@ Доминик108 В python2, 1 / 2 == 0 и -1 / 2 == -1.   -  person Brian J Murray    schedule 30.04.2021


Ответы (8)


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

Питон 3:

>>> int(-1 / 2)
0
>>> int(-3 / 2)
-1
>>> int(1 / 2)
0
>>> int(3 / 2)
1

Питон 2:

>>> int(float(-1) / 2)
0
>>> int(float(-3) / 2)
-1
>>> int(float(1) / 2)
0
>>> int(float(3) / 2)
1
person Tim    schedule 12.11.2013
comment
Это должно работать одинаково как в 2, так и в 3, ничего не импортируя из __future__, верно? - person Agostino; 30.05.2015
comment
Да, это поведение должно быть одинаковым между 2 и 3. - person Tim; 01.06.2015
comment
Примечание: использование float имеет смысл только в Python 2. В Python 3 оно бесполезно. - person Acumenus; 17.11.2016
comment
Для Python3 просто используйте: int(a/b) - person Sonal Dubey; 28.02.2020

Деление целых чисел Python по умолчанию возвращает пол (в сторону отрицательной бесконечности) без возможности изменить это. Вы можете прочитать причину, по которой BDFL .

Чтобы выполнить «округление», вы должны использовать:

>>> a=1
>>> b=2
>>> (a+(-a%b))//b
1
>>> a,b=-1,2
>>> (a+(-a%b))//b
0

Чтобы выполнить усечение до нуля и сохранить целочисленное деление, вы используете (a+(-a%b))//b, если либо a, либо b отрицательны, и деление по умолчанию, если оба положительны.

Это будет выполнять целочисленное деление и всегда округлять до нуля:

>>> a=1
>>> b=2
>>> a//b if a*b>0 else (a+(-a%b))//b
0
>>> a=-1
>>> b=2
>>> a//b if a*b>0 else (a+(-a%b))//b
0
>>> a,b=-3,2
>>> a//b if a*b>0 else (a+(-a%b))//b
-1
>>> a,b=3,2
>>> a//b if a*b>0 else (a+(-a%b))//b
1

сноска

Интересно, что C99 объявляет, что округление до нуля является значением по умолчанию:

#include <stdio.h>
int main(int argc, const char * argv[])
{

    int a=-3;
    int b=2;
    printf("a=%d, b=%d, a/b=%d\n",a,b,a/b);
    a=3;
    printf("a=%d, b=%d, a/b=%d\n",a,b,a/b);
    return 0;
}

Отпечатки:

a=-3, b=2, a/b=-1
a=3, b=2, a/b=1
person dawg    schedule 12.11.2013
comment
При округлении до нуля есть ли причина предпочесть описанный выше подход int(a / b)? - person Patrick Brinich-Langlois; 21.06.2021

Что бы это ни стоило, это мое любимое решение. Только целочисленная арифметика, одно деление и все остальное линейное время:

def integer_divide_towards_zero(a, b):
    return -(-a // b) if a < 0 else a // b

Это предполагает, что b положительно, но в большинстве приложений, которые я видел, это правда. Если вам нужно иметь дело и с отрицательным b, то функция становится немного сложнее:

def integer_divide_towards_zero(a, b):
    return -(-a // b) if (a < 0) ^ (b < 0) else a // b

Некоторые примеры результатов:

>>> integer_divide_towards_zero(11, 3)
3
>>> integer_divide_towards_zero(-11, 3)
-3
>>> integer_divide_towards_zero(6, 3)
2
>>> integer_divide_towards_zero(-6, 3)
-2
>>> integer_divide_towards_zero(11, -3)
-3
>>> integer_divide_towards_zero(-11, -3)
3
person Mark Dickinson    schedule 19.11.2013

Попробуй это. Работает только для чисел больше -1

import math

x = .5
y = -.5

print math.floor(math.fabs(x))
>> 0

print math.floor(math.fabs(y))
>> 0
person Conor Patrick    schedule 12.11.2013
comment
Это не дает правильного ответа. -1,5 должно давать -1, но это дает +1. - person Tim; 12.11.2013

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

def int0div(a, b):
    q = a // b
    if q < 0 and b*q != a:
        q += 1
    return q

Хорошие функции: он работает для любого размера int, не вносит никаких изменений в необработанный (a//b) результат без необходимости, выполняет только одно деление (% также выполняет скрытое деление) и не создает целые числа большего размера. чем входы. Они могут иметь или не иметь значения в вашем приложении; они становятся более важными (для скорости), если вы используете «большие» целые числа.

person Tim Peters    schedule 12.11.2013

Бросаю шляпу с несколькими альтернативными идеями:

Умножьте знак числа [abs(x)/x] на abs(x)/2.

(abs(x)/x)*(abs(x)/2)

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

x/2 + int(x<0)
person Community    schedule 12.11.2013
comment
Это немного ухудшает читабельность, но интересно отметить, что вы можете опустить вызов int здесь - x/2 + x<0 работает просто отлично (поскольку bool подклассы int и не переопределяют, как работают арифметические операции). - person lvc; 12.11.2013
comment
@lvc В прошлом у меня были проблемы с тем, что int + bool становилось bool, так как вы можете преобразовать int в bool и наоборот. Я просто подумал, что лучше быть более явным. - person ; 12.11.2013

Вы также можете использовать модуль Decimal как часть стандартных библиотек Python.

В частности, "Оператор целочисленного деления // ведет себя аналогично, возвращая целую часть истинного частного (усеченного в сторону нуля), а не его пол, чтобы сохранить обычное тождество x == (x // y) * y + x % г:"

>>> -7 // 4
-2
>>> Decimal(-7) // Decimal(4)
Decimal('-1')

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

Decimal был написан как решение традиционной проблемы бинарной математики в мире, ожидающем десятичных решений.

person jjisnow    schedule 13.08.2017

зачем изобретать велосипед, когда есть отличная функция math.trunc()?

import math
print(math.trunc(-3.5))
>>-3
print(math.trunc(3.5))
>>3
person jjisnow    schedule 15.09.2019