Tamsayı bölümünün davranışı nedir?


211

Örneğin,

int result;

result = 125/100;

veya

result = 43/100;

Sonuç her zaman bölümün tabanı mı olacak? Tanımlanan davranış nedir?


5
Özet: imzalı tamsayı bölümü sıfıra doğru kısalır . Negatif olmayan sonuçlar için, bu zemin ile aynıdır (-Infinity'e doğru yuvarlak). (C89'un bunu garanti etmediğine dikkat edin, cevaplara bakın.)
Peter Cordes

6
Kodun hangi tekniğin kullanılacağına dair kasıtlı bir karar vermesi gibi herkes "sıfıra doğru kes" veya "tavan" veya "zemin" diyor. Kod konuşabilseydi söylerdi"I just throw the dam fraction part in the trash and move on with life"
Timothy LJ Stewart

3
@ TimothyL.J.Stewart "Kod" kasıtlı bir karar veriyor. Spesifikasyona göre, tamsayı bölünmesi T (kesilme) -bölümüdür. Bu nedenle, modulo / kalan operatör, başka bir dilde, örneğin Python veya Ruby'den farklı şekilde implante edilir. Bkz bu diller modül operatörü yapmak farklı şekillerde listesi ve için bu programlama dilleri yaygın yollarından en az beş üzerinden listeleri div / modülo yapmaya karar şu gazeteyi.
13steinj

1
@ 13steinj Konuştuğum yorumlara göre konuşuyorum, "sıfıra doğru kısalıyor ... hayır yer ... hayır tavanı negatifse ..." bazen teknikler geleceğe insan hafızasıyla yayılmıyor istediğimiz gibi, ama sezgisel olarak "kesir kısmının fırlatıldığını" bilerek teknik noktaları elde edebilirsiniz. Teknikler ağır bir yüktür, ancak sezgi rüzgar gibi hafif ve ferahlatıcıdır, bunları uzak ve geniş olarak taşıyacağım ve gerektiğinde nereden başlayacağımı bileceğim. Bağladığınız kağıt gibi, teşekkür ederim.
Timothy LJ Stewart

Burada , Öklid bölünmesine (tamsayı bölümü ve modül operatörü arasındaki karşılıklı oyun) vurgu yaparak cevap verdim .
Picaud Vincent

Yanıtlar:


182

Sonuç her zaman bölümün tabanı mı olacak? Tanımlanan davranış nedir?

Evet, iki işlenenin tamsayı bölümü.

6.5.5 Çarpımsal operatörler

6 Tamsayılar bölündüğünde, / operatörünün sonucu, kesirli kısımları atılmış olan cebirsel bölümdür. 88) a / b bölümü temsil edilebilirse, (a / b) * b + a% b ifadesi a değerine eşit olacaktır.

ve ilgili dipnot:

88) Buna genellikle `` sıfıra doğru kesme '' denir.

Elbette dikkat edilmesi gereken iki nokta:

3 Normal aritmetik dönüşümler işlenenler üzerinde gerçekleştirilir.

ve:

5 / operatörünün sonucu, birinci işlenenin ikinciye bölünmesinden alınan bölümdür; % operatörünün sonucu kalanıdır. Her iki işlemde de, ikinci işlenenin değeri sıfırsa, davranış tanımsızdır.

[Not: Vurgu madeni]


26
... tabii ki, negatif bir sayıyı pozitif (veya vv) olarak bölmüyorsanız, bu durumda tavan olacaktır.
Will A

74
Ne döşeme ne de tavan, kesirli kısmın kesilmesi, kavramsal olarak farklı!
lornova

38
@ A: Hayır. Sıfıra doğru kesilme olarak tanımlanır. Başka bir şey çağırmak sadece karışıklığa neden olur, bu yüzden lütfen bunu yapmaktan kaçının.
Martin York

44
En azından matematiksel bir bakış açısıyla, sıfıra doğru kısaltma "eğer> 0 sonra başka bir tavana" eşittir. Ben sadece kısaltma olarak adlandırmak o kat / tavan çağırmak daha basit olduğunu düşünüyorum, ama ya da geçerlidir. Ne olursa olsun, Will A'nın puanı geçerlidir: Dirkgently'nin cevabı kısmen yanlıştır, çünkü OP'nin sonucun bölümün tabanı olduğu konusunda doğru olduğunu belirtti.
Brian

9
@Philip Potter: C89'da tanımlandığını sanmıyorum ve 1998 C ++ standardında değil. Bu, tabii ki (a / b) * b + a % b == atatmin edilmesi gerekiyordu ve mutlak değeri a % bvardı az olması a, ancak olmadığını a % bnegatif için negatifti aveya bbelirtilmedi.
David Thornley

40

Dirkgently, C99'da tamsayı bölümünün mükemmel bir açıklamasını verir , ancak C89'da negatif bir işlenen ile tamsayı bölümünün uygulama tanımlı bir yöne sahip olduğunu da bilmelisiniz.

ANSI C taslağından (3.3.5):

İşlenenlerden herhangi biri negatifse, / işlecinin sonucunun,% işlecinin sonucunun işareti gibi, cebirsel bölümden daha küçük en büyük tamsayı mı yoksa cebirsel bölümden daha büyük en küçük tamsayı mı uygulama tanımlıdır. A / b bölümü gösterilebilirse, (a / b) * b + a% b ifadesi a değerine eşit olacaktır.

Bir C89 derleyicisine takılı kaldığınızda negatif sayılara dikkat edin.

C99'un sıfıra doğru kesmeyi seçmesi eğlenceli bir gerçek çünkü FORTRAN bunu böyle yaptı. Bkz bu mesajı comp.std.c. üzerinde


2
Ve C99 taslak N1256 önsöz paragraf 5 reliable integer divisionyeni bir dil özelliği olarak bahsediyor . İnanılmaz *-*.
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

Kesme, en yaygın CPU donanımının (örn. X86) nasıl davrandığıdır, bu nedenle farklı bir seçim yapmak çılgınca olurdu. Önce gelen IDK, Fortran semantiği veya donanım davranışı, ancak bunların da aynı olması tesadüf değil.
Peter Cordes

2
@PeterCordes: En yaygın CPU donanımı, çoğu sabit tarafından kesilmiş bölme yapabildiklerinden daha hızlı katlanmış bölme yapabilir. IMHO, Standardın bunu söylemesi daha iyi olurdu expr1 / expr2ve expr1 % expr2her iki örnek expr1de aynı nesneleri aynı şekilde ve aynı şekilde birleştirdiğinde expr2, ancak aynı zamanda, kesilmiş ve katlanmış bölme seçiminin aksi belirtilmedikçe birbiriyle tutarlı olması gerekirdi . Bu, çok fazla uyumluluğu bozmadan daha verimli kod oluşturulmasına izin verirdi (ve uygulamalar eğimli ise belirli davranışları belgeleyebilir)
supercat

23

Sonucun negatif olduğu yerlerde, C yer kaplaması yerine 0'a doğru kısalır - Python tamsayı bölümünün neden her zaman buraya katlandığı hakkında bu okumayı öğrendim: Python'un Tamsayı Bölümü Zeminleri


3
(Neg% pos) negatif olmanın hiç yararlı olup olmadığını merak eden yorumu kabul ediyorum? İlgili bir not, bazı "unsignedvar> signvar" vakalarında gerekli aritmetik olarak yanlış davranış hiç yararlı olup olmadığını merak ediyorum? Her zaman doğru davranış gerektirmediğinin mantığını anlayabilirim; Yanlış davranış gerektirdiği için hiçbir gerekçe göremiyorum.
supercat

8
Döşemenin neden tamsayı bölme için doğru davranış olduğu konusunda mükemmel bir referans için +1 (C'nin tanımının aksine, kırık ve neredeyse hiç yararlı değildir).
R .. GitHub BUZA YARDIMCI DURDUR

@supercat Şunu düşünün:, filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factordeğişen değerleri ile yinelenen value. Zaman sabiti olan birinci dereceden bir düşük geçiş filtresine güzel bir tamsayı yaklaşımı yapar k... ancak bölme kesilirse ve carrynegatif değerler alırsa sadece simetriktir . Bölme için her iki davranış da zaman zaman işe yarar.
hobbs

1
@hobbs: Yukarıdaki kod sinyaller sıfırdan geçtiğinde temiz davranacağını düşünmüyorum. Eğer divkatlanmış bir bölme işleci ise ve factortuhafsa, o zamana filtered += (filter+(factor div 2)) div factorkadar olan tüm değerler için temiz ve simetrik davranış sağlar INT_MAX-(factor div 2).
supercat

@supercat olsa çalışır; bu kod bir süredir atomik saatin kontrolöründe çalıştırdığım bir şeyden birazcık damıtılmış.
hobbs

21

Evet, sonuç her zaman sıfıra doğru kesilir. En küçük mutlak değere doğru yuvarlanır.

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

İmzasız ve negatif olmayan işaretli değerler için bu, zemin ile aynıdır (-Infinity'e yuvarlama).


43
Kesme, zemin değil .
dan04

9
@ dan04: evet kat yalnızca pozitif tamsayılar için geçerli olacak :)
Leonid

13

Sonuç her zaman bölümün tabanı mı olacak?

Hayır. Sonuç değişir, ancak varyasyon yalnızca negatif değerler için gerçekleşir.

Tanımlanan davranış nedir?

Tamsayı bölme sıfıra doğru yuvarlanırken (kesmeler) kat mermilerini negatif sonsuza doğru netleştirmek için

Pozitif değerler için aynı

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

Negatif değer için bu farklı

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

0

İnsanların sorunuzu cevapladığını biliyorum, ama sıradan terimlerle:

5 / 2 = 2 // hem 5 hem de 2 tamsayı ve tamsayı bölümü her zaman ondalık sayıları kısaltır

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 // burada 5 veya 2 veya her ikisinin ondalık değeri vardır, bu nedenle alacağınız bölüm ondalık olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.