Qual é o comportamento da divisão inteira?


211

Por exemplo,

int result;

result = 125/100;

ou

result = 43/100;

O resultado será sempre o piso da divisão? Qual é o comportamento definido?


5
Resumo: a divisão inteira assinada é truncada para zero . Para resultados não negativos, é o mesmo que floor (volta para -Infinity). (Cuidado que C89 não garante isso, ver as respostas.)
Peter Cordes

6
Todo mundo fica dizendo "truncar para zero" ou "teto" ou "piso", como se o código estivesse tomando uma decisão deliberada sobre qual técnica usar. Se o código pudesse falar, diria"I just throw the dam fraction part in the trash and move on with life"
Timothy LJ Stewart

3
@ TimothyL.J.Stewart O "código" está tomando uma decisão deliberada. De acordo com a especificação, a divisão inteira deve ser a divisão T (runcation). Por esse motivo, o operador módulo / restante é implantado de maneira diferente do que se estivesse em outro idioma, por exemplo, Python ou Ruby. Veja isso para obter uma lista de diferentes maneiras pelas quais as linguagens executam o operador modulo e este artigo que lista pelo menos cinco das maneiras comuns pelas quais as linguagens de programação decidem executar div / modulo.
23-18

1
@ 13steinj Estou falando coloquialmente pelos comentários que estavam se transformando em "é truncado em direção a zero ... não é no chão ... não se for negativo no teto ..." às ​​vezes os detalhes técnicos não se propagam para o futuro com a memória humana como desejamos, mas sabendo intuitivamente que a "parte da fração é descartada", você pode derivar os pontos técnicos. Os detalhes técnicos são um fardo pesado, mas a intuição é leve e refrescante como o vento, levarei aqueles longe e, quando necessário, saberei por onde começar. Como o artigo que você vinculou, obrigado.
Timothy LJ Stewart

Eu respondi aqui com ênfase na divisão euclidiana (inter-jogo entre divisão inteira e operador de módulo).
Picaud Vincent

Respostas:


182

O resultado será sempre o piso da divisão? Qual é o comportamento definido?

Sim, quociente inteiro dos dois operandos.

6.5.5 Operadores multiplicativos

6 Quando números inteiros são divididos, o resultado do operador / é o quociente algébrico com qualquer parte fracionária descartada. 88) Se o quociente a / b for representável, a expressão (a / b) * b + a% b será igual a.

e a nota de rodapé correspondente:

88) Isso geralmente é chamado de truncamento em direção a zero.

É claro que dois pontos a serem observados são:

3 As conversões aritméticas comuns são realizadas nos operandos.

e:

5 O resultado do operador / é o quociente da divisão do primeiro operando pelo segundo; o resultado do operador% é o restante. Nas duas operações, se o valor do segundo operando for zero, o comportamento será indefinido.

[Nota: ênfase minha]


26
... a menos, claro, você esteja dividindo um número negativo por um positivo (ou vv); nesse caso, será o teto.
Will A

74
Não é piso nem teto, é truncamento de parte fracionária, é conceitualmente diferente!
Lornova 30/08/10

38
@ Will A: Não. É definido como truncamento em direção a zero. Se você chamar qualquer outra coisa, isso apenas aumentará a confusão; portanto, evite fazê-lo.
Martin York

44
Pelo menos de uma perspectiva matemática, o truncamento em direção a zero é equivalente a "se> 0, então o piso é outro". Eu acho que apenas chamá-lo de truncamento é mais simples do que chamá-lo de piso / teto, mas qualquer um deles é válido. Independentemente disso, o argumento de Will A é válido: a resposta de Dirkgently está parcialmente incorreta, pois ele afirmou que o OP está certo sobre o resultado ser o piso da divisão.
Brian

9
@ Philip Potter: Eu não acho que foi definido no C89, e não está no padrão C ++ de 1998. Nesses, é claro que (a / b) * b + a % b == atinha que ser satisfeito, e o valor absoluto de a % btinha que ser menor que a, mas se a % bera negativo para negativo aou bnão era especificado.
David Thornley

40

Dirkgently fornece uma excelente descrição da divisão inteira no C99, mas você também deve saber que na C89 a divisão inteira com um operando negativo tem uma direção definida pela implementação.

Do rascunho ANSI C (3.3.5):

Se um dos operandos for negativo, se o resultado do operador / é o maior inteiro menor que o quociente algébrico ou o menor inteiro maior que o quociente algébrico é definido pela implementação, como é o sinal do resultado do operador%. Se o quociente a / b for representável, a expressão (a / b) * b + a% b será igual a.

Portanto, tenha cuidado com números negativos quando estiver preso a um compilador C89.

É um fato divertido que o C99 tenha escolhido o truncamento para zero, porque foi assim que a FORTRAN fez isso. Veja esta mensagem em comp.std.c.


2
E o rascunho C99 N1256 do parágrafo 5 do prefácio menciona reliable integer divisioncomo um novo recurso de idioma. Incrível *-*.
Ciro Santilli

O truncamento é como o hardware da CPU mais comum (por exemplo, x86) se comporta, portanto seria uma loucura fazer uma escolha diferente. IDK que veio primeiro, semântica do Fortran ou comportamento do hardware, mas não é coincidência que os mesmos também.
Peter Cordes

2
@ PeterCordes: O hardware de CPU mais comum poderia fazer a divisão do piso pela maioria das constantes mais rapidamente do que a divisão de truncamento. IMHO, teria sido melhor para o Padrão dizer isso expr1 / expr2e expr1 % expr2deve ser consistente um com o outro quando ambas as instâncias expr1combinam os mesmos objetos da mesma maneira e da mesma forma expr2, mas a escolha de truncar versus divisão com piso não é especificada. Isso permitiria uma geração de código mais eficiente sem quebrar muita compatibilidade (e as implementações podem documentar um comportamento específico, se necessário) #
3012

23

Onde o resultado é negativo, C trunca para 0 em vez de para o piso - aprendi esta leitura sobre por que a divisão inteira do Python sempre aparece aqui: Por que a divisão inteira do Python flutua


3
Eu concordo com o comentário perguntando se ter (neg% pos) negativo é útil? Em uma nota relacionada, gostaria de saber se o comportamento aritmético incorreto necessário em alguns casos de "unsignedvar> assinadovar" é útil? Eu posso entender a justificativa para não exigir um comportamento sempre correto; Não vejo justificativa para exigir comportamento errado.
Supercat

8
+1 para uma excelente referência sobre por que o piso é o comportamento correto para a divisão inteira (ao contrário da definição de C, que é quebrada e quase nunca é útil).
G .. GitHub Pare de ajudar o gelo

@ supercat Considere:, filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factoriterado com a alteração dos valores de value. Ele faz uma boa aproximação de número inteiro a um filtro lowpass de primeira ordem com constante de tempo k... mas é simétrico apenas se a divisão estiver truncando e carryobtiver valores negativos. Ambos os comportamentos de divisão são úteis de tempos em tempos.
Hbbs #:

1
@ Hobbs: Eu não acho que o código acima se comportaria corretamente quando os sinais cruzarem zero. Se divfor um operador de divisão com piso e factorfor ímpar, filtered += (filter+(factor div 2)) div factorproduziria um comportamento limpo e simétrico para todos os valores até INT_MAX-(factor div 2).
Supercat

@ supercat ele funciona embora; esse código é apenas um pouco destilado de algo que tive durante algum tempo no controlador de um relógio atômico.
hobbs

21

Sim, o resultado é sempre truncado para zero. Ele arredondará para o menor valor absoluto.

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

Para valores assinados não assinados e não negativos, é o mesmo que piso (arredondamento para -Infinito).


43
Truncamento, não no chão.
precisa saber é o seguinte

9
@ dan04: piso sim seria válida apenas para números inteiros positivos :)
Leonid

13

O resultado será sempre o piso da divisão?

Não. O resultado varia, mas a variação ocorre apenas para valores negativos.

Qual é o comportamento definido?

Para deixar claro que o piso é arredondado para o infinito negativo, enquanto a divisão inteira é arredondada para zero (trunca)

Para valores positivos eles são os mesmos

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

Para valor negativo, isso é diferente

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

0

Sei que as pessoas responderam sua pergunta, mas em termos leigos:

5 / 2 = 2 // como 5 e 2 são números inteiros e a divisão de números inteiros sempre trunca decimais

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 // aqui 5 ou 2 ou ambos tem decimal, portanto, o quociente que você obterá será decimal.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.