Tamsayı bölümü: Nasıl bir çift üretersiniz?


248

Bu kod bloğu için:

int num = 5;
int denom = 7;
double d = num / denom;

değeri dIS 0.0. Döküm ile çalışmaya zorlanabilir:

double d = ((double) num) / denom;

Ancak doğru doublesonucu almanın başka bir yolu var mı? Ne olabileceğini bilen ilkelleri dökmeyi sevmiyorum.



9
"int" i iki katına çıkarmak güvenlidir, hassasiyet kaybı olmadan her zaman aynı değeri elde edersiniz.
Peter Lawrey

1
Aşağıdakilerin bölme için derleyici tarafından atılan doğru adımlar olup olmadığını bilmek istiyorum: 1) num'u float'a dökmek 2) cast denomunu yüzmek için de 2) num'u mezhebe bölmek. Lütfen hatalı olduğumu bana bildirin.
mannyee

Yanıtlar:


156
double num = 5;

Bu oyuncu kadrosundan kaçınır. Ancak, dönüşüm dönüşümlerinin iyi tanımlanmış olduğunu göreceksiniz. Tahmin etmek zorunda değilsiniz, sadece JLS'yi kontrol edin . int to double, genişleyen bir dönüşümdür. Gönderen §5.1.2 :

İlkel dönüşümleri genişletmek, sayısal bir değerin toplam büyüklüğü hakkında bilgi kaybetmez.

[...]

Bir int değerinin veya uzun bir değerin kayan değere veya uzun bir değerin ikiye çevrilmesi, hassasiyet kaybına neden olabilir; sonuç, değerin en az önemli bitlerinden bazılarını kaybedebilir. Bu durumda, sonuçta elde edilen kayan nokta değeri, IEEE 754 en yakın yuvarlak mod (§4.2.4) kullanılarak tamsayı değerinin doğru yuvarlatılmış bir versiyonu olacaktır .

5 tam olarak bir çift olarak ifade edilebilir.


60
+1. Dökmekten korkmayı bırak. Nasıl çalıştığını öğrenin. Her şey iyi tanımlanmış.
Mark Peters

1
@FabricioPH Bu her durumda ve * 1.0 çözümüyle aynı şekilde çalışır.
Vitruvius

3
@Saposhiente Çalışmanın ötesine geçiyor ya da gitmiyor. Bir değişkenin türünü değiştirmek bana kirli bir kod gibi geliyor. Tamsayı OLMASI GEREKEN bir şeyiniz varsa ve sadece matematik işlemini gerçekleştirmek için bir şamandıra temsilini değiştirirseniz, kendinizi riske atıyor olabilirsiniz. Ayrıca bazı bağlamlarda değişkeni bir tamsayı olarak okumak, kodun anlaşılmasını kolaylaştırır.
Fabricio PH

2
@FabricioPH ile çarpmak 1.0, sonucun türünü hala farklı bir şekilde değiştirir. 'Bana kirli kod görünüyor', çarpmanın 1.0gerçekten daha iyi olduğuna inandığınız senaryo (lar) ın (veya bunun neden olabileceğini) açıklamıyor.
Matthew Flaschen

4
@FabricioPH Siz ve OP, bir (double)numşekilde değişiklik yapan yanlış inanç ("Değişkenin türünü değiştirme" diyorsunuz) altında çalışıyorsunuz num. Öyle değil - ifadenin bağlamı için geçici bir çift oluşturur.
Paul Tomblin

100

Döküm ilkellerinin sorunu nedir?

Herhangi bir nedenden dolayı döküm yapmak istemiyorsanız,

double d = num * 1.0 / denom;

63
... çarpma işleminden önce örtük bir oyuncu seçimi
Alice Purcell

2
Çoğu durumda bu, diğer değişkenin türünü değiştirmekten daha iyidir.
Fabricio PH

3
@FabricioPH Alıntı yapmak için bir kaynağınız yoksa hiçbir şey bunun doğru olduğunu göstermez.
Vitruvius

1
@Saposhiente diğer benzer yorumunda yanıtladı
Fabricio PH

1
"D" postfix'i de kullanabilirsiniz (aynı örtülü oyuncu kadrosunu gerçekleştirmek için); - örneğin:double d = num * 1D / denom;
BrainSlugs83

73

Ne olabileceğini bilen ilkelleri dökmeyi sevmiyorum.

Neden ilkelleri dökme konusunda mantıksız bir korkunuz var? Bir döküm hiçbir şey kötü olacak intbir etmek double. Nasıl çalıştığından emin değilseniz, Java Dil Spesifikasyonu'nda arayın . Bir Döküm intTo doublea, genişleyen ilkel dönüşüm .

Pay yerine paydayı dökerek ekstra parantez çiftinden kurtulabilirsiniz:

double d = num / (double) denom;

2
sen de yapabilirsin double d = (double) num / denom;... (Tamam, bu önceliğe bağlıdır)
user85421

27

Formülünüz değişirse değişkenlerden birinin türünü değiştirirseniz, tekrar çifte gizlice girmeniz gerektiğini unutmayın; çünkü bu değişken hesaplamanın bir parçası olmayı bırakırsa sonuç dağınıktır. Hesaplamada bir alışkanlık yapıyorum ve yanına bir yorum ekliyorum.

double d = 5 / (double) 20; //cast to double, to do floating point calculations

Sonucu yayınlamanın sonuç vermeyeceğini unutmayın

double d = (double)(5 / 20); //produces 0.0

17

Yüzen nokta Math ile yapılacak işlemi zorlamak için kayan tam sayı / her iki tamsayıyı birini döküm. Aksi takdirde her zaman Math tamsayı tercih edilir. Yani:

1. double d = (double)5 / 20;
2. double v = (double)5 / (double) 20;
3. double v = 5 / (double) 20;

Sonucu yayınlamanın sonuç vermeyeceğini unutmayın. Çünkü birinci bölüm öncelik kuralına göre yapılır.

double d = (double)(5 / 20); //produces 0.0

Düşündüğünüz gibi dökümde herhangi bir sorun olduğunu düşünmüyorum.


10

Türü Döküm Tek Yoldur


doubleTamsayı bir bölüm üretmek - döküm yapmanın başka bir yolu yoktur (belki bunu açıkça yapmayacaksınız, ancak olacak).

Şimdi, kesin doubledeğer elde etmeye çalışabileceğimiz birkaç yol var (nerede numve denomne inttür ve tabii ki döküm ile ) -

  1. açık döküm ile:

    • double d = (double) num / denom;
    • double d = ((double) num) / denom;
    • double d = num / (double) denom;
    • double d = (double) num / (double) denom;

Ama değil double d = (double) (num / denom);

  1. örtülü döküm ile:

    • double d = num * 1.0 / denom;
    • double d = num / 1d / denom;
    • double d = ( num + 0.0 ) / denom;
    • double d = num; d /= denom;

ama değil double d = num / denom * 1.0;
ve değildouble d = 0.0 + ( num / denom );


2

gibi bir şey kullanın:

double step = 1d / 5;

(1d, iki katına çıktı)


5
1d oyuncular değil, sadece bir beyan.
Sefier Tang

0

İşlemleri tamamlamayı düşünebilirsiniz. Örneğin:

class Utils
{
    public static double divide(int num, int denom) {
        return ((double) num) / denom;
    }
}

Bu, kadronun tam olarak istediğinizi yapıp yapmadığını (sadece bir kez) aramanıza izin verir. Bu yöntem, istediğinizi yapmaya devam etmesini sağlamak için testlere de tabi tutulabilir. Ayrıca, doğru sonuca neden olduğu sürece bölünmeye neden olmak için hangi hileyi kullandığınız da önemli değildir (burada cevaplardan herhangi birini kullanabilirsiniz). İki tamsayıyı bölmeniz gereken her yerde, şimdi Utils::dividedoğru şeyi yaptığını arayabilir ve güvenebilirsiniz.



0

Bunu yapmanın en iyi yolu

int i = 3;
Double d = i * 1.0;

d is 3.0 now.
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.