Neden iki tamsayı bölmek ikiye katlama olarak atandığında doğru değeri vermiyor?


110

Nasıl oluyor da aşağıdaki parçada

int a = 7;
int b = 3;
double c = 0;
c = a / b;

cBeklenebileceği gibi 2,3333 yerine 2 değerine sahip olur. Eğer ave bçift kişilik, cevap 2.333 dönüp gelmez. Ama kesinlikle c zaten bir çift olduğu için tamsayılarla çalışması gerekirdi?

Peki int/int=doubleneden işe yaramıyor?


Yanıtlar:


161

Bunun nedeni operator/, 2 ints alan ve bir int. A doubledöndüren sürümü kullanmak için , s'lerden doubleen az birinin intaçıkça bir double.

c = a/(double)b;

9
Ben açıkça hem dönüştürmek için tercih ediyorum ave bhiç doublenetlik için basitçe, ama gerçekten önemli değil.
John Dibling

31
Soru C ++ olarak etiketlendiğinden, C dökümünden çok static_cast <> görmeyi tercih ederim.
Martin York

16
Kişisel olarak, C tarzı dökümlerin daha net olduğunu hissediyorum (diğer yaygın dillerin çoğunda döküm C tarzı şekilde yapılır). static_cast<>bana hep uzun soluklu göründü. İlkel durumunda, gerçekten almanın herhangi bir tehlike yoktur static_cast<>ve reinterpret_cast<>karışık up.
Chad La Guardia

6
@ Tux-D: Aritmetik yayınlar için mi? static_castBu durumda kaçınmayı ve bunun yerine C tarzı döküm kullanmayı tercih ederim . Burada C ++ tarzı yayınlar kullanmanın bir yararı yoktur ve kodu C tarzı yayınlardan çok daha fazla karıştırırlar. Aritmetik döküm, tam olarak C-tarzı yayınların mükemmel bir şekilde uygun olduğu ve aslında diğer yayınlardan daha uygun olduğu bağlamdır.
AnT

19
Bazen yazarak "C tarzı oyuncu olmayan" insanları alt edebilirsiniz double(b). Açık bir yapıcı çağrısıyla aynı göründüğü için bunun bir dönüşüm olduğunun her zaman farkına varmazlar.
Steve Jessop

12

İşte burada:

a) İki saniyeyi bölmek inther zaman tamsayı bölme yapar. Yani a/bsizin durumunuzdaki sonucu yalnızca bir int.

Tutmak ave s bolarak istiyorsanız int, ancak bunları tam olarak bölmek istiyorsanız, en az birini ikiye katlamanız gerekir: (double)a/bveya a/(double)bveya (double)a/(double)b.

b) ca olduğundan double, atamada bir değeri kabul edebilir int: intotomatik olarak dönüştürülür doubleve atanır c.

c) Atama sırasında, 'nin sağındaki ifadenin önce= hesaplandığını (yukarıdaki kural (a)' ya göre ve solundaki değişken dikkate alınmadan ) ve sonra solundaki değişkene atandığını unutmayın (( b) yukarıda). Bunun resmi tamamladığına inanıyorum.==


11

Çok az istisna dışında (sadece birini düşünebiliyorum), C ++ ifadenin kendisinden bir ifadenin (veya alt ifadenin) tüm anlamını belirler. İfadenin sonuçlarıyla ne yaptığınız önemli değil. Sizin durumunuzda, ifadede görünürde a / bbir şey yok double; herşey int. Yani derleyici tamsayı bölmesini kullanır. Yalnızca sonucu aldığında onunla ne yapacağını düşünür ve onu dönüştürür double.


3
Aklıma gelen tek istisna, bir işaretçi alırken bir işlev aşırı yüklemesi seçmektir - değeri, &funcnameonu hangi türe dönüştürdüğünüze bağlıdır.
Steve Jessop

2
@Steve Jessop Benim de düşünebildiğim tek istisna bu. (Ancak standardın boyutu ve karmaşıklığı göz önüne alındığında, hiçbirini kaçırmadığıma yemin etmek istemem.)
James Kanze

6

cbir doubledeğişkendir, ancak ona atanan intdeğer bir değerdir çünkü iki ints'nin bölünmesinden kaynaklanır , bu da size "tamsayı bölümü" verir (kalanı bırakarak). Çizgi içinde ne olur c=a/bise

  1. a/b değerlendirilir, geçici bir tür oluşturur int
  2. ctipe dönüştürüldükten sonra geçici değer atanır double.

Değeri a/b, bağlamına (atama double) atıfta bulunulmadan belirlenir .


6

İki tamsayıyı böldüğünüzde, onu ikiye katlamanızdan bağımsız olarak sonuç bir tam sayı olacaktır.


5

C ++ dilinde, alt ifadenin sonucu çevreleyen bağlamdan asla etkilenmez (bazı nadir istisnalar dışında). Bu, dilin dikkatle izlediği ilkelerden biridir. İfade , bu c = a / balt ifadenin a / bdışındaki herhangi bir şeyden bağımsız olarak yorumlanan bağımsız bir alt ifade içerir. Dil, sonucu daha sonra a double. a / bbir tamsayı bölümüdür. Başka hiçbir şeyin önemi yok. Dil spesifikasyonunun birçok köşesinde bu ilkenin izlendiğini göreceksiniz. C ++ (ve C) 'nin çalışma şekli budur.

Yukarıda bahsettiğim bir istisna örneği, aşırı fonksiyon yüklemesi olan durumlarda fonksiyon işaretçisi ataması / başlatmasıdır

void foo(int);
void foo(double);

void (*p)(double) = &foo; // automatically selects `foo(fouble)`

Bu, bir atamanın / ilklendirmenin sol tarafının sağ tarafın davranışını etkilediği bir bağlamdır. (Ayrıca, diziye başvuru başlatma, benzer davranışın başka bir örneği olan dizi türü bozulmasını önler.) Diğer tüm durumlarda sağ taraf, sol tarafı tamamen yok sayar.


4

/Operatör tamsayı bölme ya da kayan nokta bölümü için kullanılabilir. Ona iki tamsayı işlenen veriyorsunuz, yani tamsayı bölme yapıyor ve sonra sonuç bir ikiye bölünüyor.


2

Bu teknik olarak dile bağlıdır, ancak hemen hemen tüm diller bu konuyu aynı şekilde ele alır. Bir ifadede iki veri türü arasında bir tür uyuşmazlığı olduğunda, çoğu dil =, diğer taraftaki verileri önceden tanımlanmış bir dizi kurala göre eşleştirmek için veriyi bir tarafına dönüştürmeye çalışır.

Aynı türden iki sayıyı bölerken (tamsayılar, çiftler vb.) Sonuç her zaman aynı türden olacaktır (bu nedenle 'int / int' her zaman int ile sonuçlanacaktır).

Bu durumda double var = integer result , tamsayı sonucunu hesaplamadan sonra ikiye katlayan sonuca sahip olursunuz, bu durumda kesirli veriler zaten kaybolur. (çoğu dil, tür hatalarını bir istisna veya hata oluşturmadan önlemek için bu atamayı yapar).

Sonucu bir çift olarak tutmak isterseniz, sahip olduğunuz bir durum yaratmak isteyeceksiniz. double var = double result

Bunu yapmanın en kolay yolu, bir denklemin sağ tarafındaki ifadeyi ikiye katlamaya zorlamaktır:

c = a/(double)b

Bir tamsayı ve bir çift arasındaki bölme, tam sayının ikiye çevrilmesiyle sonuçlanacaktır (matematik yaparken, derleyicinin genellikle en özel veri tipine "yukarı yayın" yapacağını unutmayın, bu veri kaybını önlemek içindir).

Yukarıdan sonra, abir çift olarak sarılacak ve şimdi iki çift arasında bölünme var. Bu, istenen bölümü ve görevi yaratacaktır.

TEKRAR, bunun dile özgü olduğunu (ve hatta derleyiciye özgü olabileceğini) unutmayın, ancak hemen hemen tüm diller (kesinlikle aklıma gelmeyen tüm diller) bu örneği aynı şekilde ele alır.


Bu soru [C ++] olarak etiketlenmiştir ve C ++ Standardı bunun tam olarak nasıl çalıştığını belirtir. "Dile özgü" ile ne demek istediğinizden emin değilim ve kesinlikle derleyiciye özgü değildir, hiçbir derleyici uzantısının devreye girmediğini varsayarsak.
John Dibling

Ayrıca "double var = tamsayı sonucu, double var'ı int'e çeviren sonuç" demek de yanlıştır. Double bir int'e dönüştürülmez. İnt sonucu, double türüne dönüştürülür.
John Dibling

Derleyici uzantılarının olasılığına izin veriyordum (aslında bu sorunu bir zamanlar ortamımın sonuçları "yanlış yayınladığı" ve nedenini anlayamadım) yaşadım). Ve sonuç, bazı dillerde aynı döküm kurallarına uymadığı için dile özgüdür. Bunun C ++ 'ya özgü bir etiket olduğunu düşünmedim. "Double var = integer sonuç" yorumu konusunda haklısınız. Bunu yansıtmak için düzenlendi. Teşekkür ederim!
matthewdunnam

0

Önemli olan hesaplama unsurlarından birinin float-double türü olmasıdır. Daha sonra çift sonuç almak için bu öğeyi aşağıda gösterildiği gibi dökmeniz gerekir:

c = static_cast<double>(a) / b;

veya c = a / static_cast (b);

Veya doğrudan oluşturabilirsiniz:

c = 7.0 / 3;

Bir float-double türünün bir tamsayıya bölünmesini belirtmek için hesaplama öğelerinden birinin ".0" olması gerektiğini unutmayın. Aksi takdirde c değişkeninin double olmasına rağmen sonuç da sıfır olacaktır.


Cevabınız, diğer 9 cevaptan hiçbirinin halihazırda mevcut olmadığına ne getiriyor?
bolov
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.