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.
... 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.
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
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=-25/2=2
Para valores assinados não assinados e não negativos, é o mesmo que piso (arredondamento para -Infinito).
"I just throw the dam fraction part in the trash and move on with life"
Respostas:
Sim, quociente inteiro dos dois operandos.
e a nota de rodapé correspondente:
É claro que dois pontos a serem observados são:
e:
[Nota: ênfase minha]
fonte
(a / b) * b + a % b == a
tinha que ser satisfeito, e o valor absoluto dea % b
tinha que ser menor quea
, mas sea % b
era negativo para negativoa
oub
não era especificado.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):
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.
fonte
reliable integer division
como um novo recurso de idioma. Incrível*-*
.expr1 / expr2
eexpr1 % expr2
deve ser consistente um com o outro quando ambas as instânciasexpr1
combinam os mesmos objetos da mesma maneira e da mesma formaexpr2
, 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) #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
fonte
filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factor
iterado com a alteração dos valores devalue
. Ele faz uma boa aproximação de número inteiro a um filtro lowpass de primeira ordem com constante de tempok
... mas é simétrico apenas se a divisão estiver truncando ecarry
obtiver valores negativos. Ambos os comportamentos de divisão são úteis de tempos em tempos.div
for um operador de divisão com piso efactor
for ímpar,filtered += (filter+(factor div 2)) div factor
produziria um comportamento limpo e simétrico para todos os valores atéINT_MAX-(factor div 2)
.Sim, o resultado é sempre truncado para zero. Ele arredondará para o menor valor absoluto.
Para valores assinados não assinados e não negativos, é o mesmo que piso (arredondamento para -Infinito).
fonte
Não. O resultado varia, mas a variação ocorre apenas para valores negativos.
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
Para valor negativo, isso é diferente
fonte
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 decimais5.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.fonte