Int bölme: Neden 1/3 == 0 sonucudur?


107

Bu kodu yazıyordum:

public static void main(String[] args) {
    double g = 1 / 3;
    System.out.printf("%.2f", g);
}

Sonuç 0'dır. Bu neden oluyor ve bu sorunu nasıl çözebilirim?

Yanıtlar:


147

İki işlenen (1 ve 3) tam sayıdır, bu nedenle tam sayı aritmetik (burada bölme) kullanılır. Sonuç değişkeninin çift olarak bildirilmesi, bölmeden sonra örtük bir dönüşümün gerçekleşmesine neden olur .

Elbette tamsayı bölme, sıfıra yuvarlanmış bölmenin gerçek sonucunu verir. Sonucu0.333... burada 0'a yuvarlanır. (İşlemcinin aslında herhangi bir yuvarlama yapmadığını unutmayın, ancak yine de bu şekilde düşünebilirsiniz.)

Ayrıca, her iki işlenen (sayı) yüzer olarak verildiğinde; 3.0 ve 1.0 veya hatta sadece ilk , daha sonra kayan nokta aritmetiği kullanılır, size verir 0.333....


33
+1 ve her zaman aşağı yuvarlanır. int i = .99999999int'i 0'a ayarlar. Daha spesifik olarak, tamsayı kısmını alır ve gerisini atar.
Byron Whitlock

37
Sıfırdan büyük değerler için "aşağıya doğru" olan "sıfıra doğru" yuvarlar. (+0,9, 0'a yuvarlanır, -0,9 da 0'a yuvarlanır)
Adrian Smith

@Byron: Evet, aynen. Bölme çok farklı uygulandığından işlemcinin aslında herhangi bir yuvarlama yaptığına inanmıyorum, ancak bu şekilde düşünmek kullanışlı.
Noldorin

16
Hayır, yuvarlama değil: Kesme
Basil Bourque

3
@BasilBourque Java terminolojisinde yuvarlamaDOWN sıfıra doğru. Yuvarlama FLOOR, negatif sonsuza doğrudur.
Andreas

23

1/3 her iki taraf da tam sayı olduğundan tamsayı bölme kullanır.

Bunlardan İhtiyacınız en az biri olmak floatveyadouble .

Sorunuz gibi kaynak koddaki değerleri giriyorsanız şunları yapabilirsiniz 1.0/3; 1.0Bir iki katı.

Eğer başka bir yerden değerleri alırsanız kullanabilirsiniz (double)açmak için intbir içine double.

int x = ...;
int y = ...;
double value = ((double) x) / y;

10

Açıkça bir double

double g = 1.0/3.0

Bunun nedeni, Java'nın tamsayı bölme işlemini için 1ve 3siz onları tamsayı sabitleri olarak girdiğiniz andan itibaren kullanmasıdır.


2

kullanmalısın

double g=1.0/3;

veya

double g=1/3.0;

Tamsayı bölümü tamsayı döndürür.


2

Çünkü tamsayı bölme yapıyorsun.

@Noldorin'in dediği gibi, her iki operatör de tamsayı ise, tamsayı bölme kullanılır.

Sonuç 0.33333333 bir tamsayı olarak gösterilemez, bu nedenle sonuca yalnızca tamsayı kısmı (0) atanır.

Operatörlerden herhangi biri bir double/ ise float, kayan nokta aritmetiği yer alacaktır. Ancak bunu yaparsanız aynı sorunu yaşarsınız:

int n = 1.0 / 3.0;

1

Çünkü 1 ve 3'ü tam sayı olarak ele aldığı için sonucu 0'a yuvarlayarak bir tamsayı olur.

Aradığınız sonucu elde etmek için, java'ya açıkça sayıların iki katı olduğunu söyleyin:

double g = 1.0/3.0;

1

1'i bir float yapın ve float bölümü kullanılacak

public static void main(String d[]){
    double g=1f/3;
    System.out.printf("%.2f",g);
}

1

JAVA'daki dönüştürme oldukça basittir ancak biraz anlayış gerektirir. Tamsayı işlemleri için JLS'de açıklandığı gibi :

Kaydırma operatörü dışındaki bir tamsayı operatörünün en az bir uzun işlenen tipine sahip olması durumunda, işlem 64 bitlik hassasiyet kullanılarak gerçekleştirilir ve sayısal operatörün sonucu uzun tiptedir. Diğer işlenen uzun değilse, önce sayısal yükseltme (§5.6) ile long yazmak için genişletilir (§5.1.5).

Ve bir örnek her zaman JLS'yi çevirmenin en iyi yoludur;)

int + long -> long
int(1) + long(2) + int(3) -> long(1+2) + long(3)

Aksi takdirde, işlem 32 bitlik kesinlik kullanılarak gerçekleştirilir ve sayısal operatörün sonucu int türündedir. İşlenenlerden herhangi biri bir int değilse, önce sayısal yükseltmeyle int türüne genişletilir.

short + int -> int + int -> int

Eclipse kullanan küçük bir örnek, iki " shortnin eklenmesinin bile o kadar kolay olmayacağını göstermek için:

short s = 1;
s = s + s; <- Compiling error

//possible loss of precision
//  required: short
//  found:    int

Bu, olası bir hassasiyet kaybına sahip bir döküm gerektirecektir.

Aynısı kayan nokta operatörleri için de geçerlidir

Bir sayısal operatörün işlenenlerinden en az biri double türünde ise, işlem 64-bit kayan noktalı aritmetik kullanılarak gerçekleştirilir ve sayısal operatörün sonucu double türünde bir değerdir. Diğer işlenen bir double değilse, önce sayısal yükseltmeyle double (§5.6) yazmak için genişletilir (§5.1.5).

Böylece terfi şamandırada iki katına çıkarılır.

Hem tam sayı hem de kayan değerin karışımı, belirtildiği gibi kayan değerlerle sonuçlanır

Bir ikili operatörün işlenenlerinden en az biri kayan nokta tipindeyse, diğeri integral olsa bile işlem bir kayan nokta işlemidir.

Bu, ikili operatörler için doğrudur ancak "Atama Operatörleri" için geçerli değildir. +=

Bunu kanıtlamak için basit bir çalışma örneği yeterlidir

int i = 1;
i += 1.5f;

Nedeni, burada yapılan örtük bir döküm var, bu şu şekilde yürütülecek

i = (int) i + 1.5f
i = (int) 2.5f
i = 2

1

1 ve 3 Contants tamsayı vardır ve Java bir tamsayı bölme yapar, böylece size yazmak zorunda çift sabitleri yazmak istiyorsanız hangi ettiği sonuç 0'dır 1.0ve 3.0.


1

En kolay çözüm sadece bunu yapmaktır

double g = ((double) 1 / 3);

1.0 / 3.0 girmediğiniz için bunun yaptığı şey, Java'nın bunun Tamsayı bölümü olduğunu varsaydığından ve dönüşümü daraltmak anlamına gelse bile bunu yapacağından, bunu manuel olarak çift veri türüne dönüştürmenize izin vermektir. Bu, döküm operatörü olarak adlandırılan şeydir.


1

Bunu ben yaptım.

double g = 1.0/3.0;
System.out.printf("%gf", g);

Çift hesaplama yaparken .0 kullanın, aksi takdirde Java, Tamsayı kullandığınızı varsayacaktır. Bir Hesaplama herhangi bir miktarda çift değer kullanırsa, çıktı bir çift değer olacaktır. Tüm Tamsayılar ise, çıktı bir Tamsayı olacaktır.


0

(1/3), Tamsayı bölümü anlamına gelir, bu nedenle bu bölümden ondalık değer alamazsınız. Bu sorunu çözmek için şunları kullanın:

public static void main(String[] args) {
        double g = 1.0 / 3;
        System.out.printf("%.2f", g);
    }

0
public static void main(String[] args) {
    double g = 1 / 3;
    System.out.printf("%.2f", g);
}

Hem 1 hem de 3 tam sayı olduğundan, sonuç yuvarlanmamıştır, ancak kesilmiştir. Yani kesirleri yok sayarsınız ve sadece bütünleri alırsınız.

Bundan kaçınmak için 1 veya 3 numaralarınızdan en az birini 1.0 ve / veya 3.0 ondalık formunda bulundurun.


0

Şunu deneyin:

public static void main(String[] args) {
    double a = 1.0;
    double b = 3.0;
    double g = a / b;
    System.out.printf(""+ g);
}

Lütfen yalnızca kod yanıtlarını göndermeyin, kodunuzun ne yaptığını ve sorunun sorununu nasıl (ve neden) çözdüğünü açıklayın. Ayrıca bunun, mevcut yanıtları yükseltilmiş 8 yıllık bir soru olduğunu ve yanıtınızın mevcut yanıtlara herhangi bir değer katıp katmadığını düşünün.
Mark Rotteveel

-1

"Double g = 1.0 / 3.0;" yapın yerine.


Sadece merak ediyorum ... bu cevabın nesi yanlış? Sorunla ilk karşılaştığımda bu yaklaşımı kullandım. Bu çözümde neyin yanlış olduğuna dair bir açıklama takdir edilecektir. Şimdiden teşekkürler.
Bay Port St Joe

@ Mr.PortStJoe Soruyu soran kişiye herhangi bir ayrıntı sağlamaz. En yüksek puan alan cevaba baktığımızda, NEDEN olduğunu da açıkladıklarını görebiliriz. Cevap teknik olarak doğru olsa da, kullanışlılığı sınırlı olarak görülebilir.
Andrew T Finnell

-1

Diğer pek çok kişi de asıl meseleyi belirtmekte başarısız oldu:

Yalnızca tam sayılar üzerinde yapılan bir işlem, işlemin sonucunu bir tam sayıya çevirir.

Bu ille nokta sonuçlarını yüzen bu demek ki, olabilir bir tamsayı olarak gösterilecektir, kesilecek (ondalık kısmı kapalı sarkık).

Döküm nedir sormak (tiplemeleri / tip dönüşümü)?

Dilin uygulanmasına göre değişir, ancak Wikipedia oldukça kapsamlı bir görüşe sahip ve zorlama hakkında konuşuyor sorunuzu yanıtlarken çok önemli bir bilgi olan .

http://en.wikipedia.org/wiki/Type_conversion


Bu cevap kusurlu. 1/2Hedef dilde (java) olduğu gibi , tamsayı bir tamsayı bölünmesine dahil olan Tip Döküm veya Tip Dönüştürme yoktur . Sadece bir tamsayı bölümü çağırırsınız, bu da bir tamsayı sonucuyla sonuçlanır. Tip Döküm sırf yukarı-dönüşüm olduğunu intbir etmek doubleatama sırasında.
YoYo

@YoYo 0.5 tam sayı mı diyorsun? Sanmıyorum dostum.
sova

1
bu arkadaş hakkında hiçbir şey söylemedi 0.5. Basitçe, Java'da, 1/2sıfır tamsayı ile sonuçlanan bir tamsayı bölümüdür. Bir double'a sıfır atayabilirsiniz, bu bir 0.0double da olsa yine de sıfır olacaktır .
YoYo
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.