2014-07-15 16 views
15

Tôi đã cố gắng chuyển đổi int và dài này, nơi tôi đã thử gán một biến số int cho biến số long. Mã này là như sau:int để phân công dài

public static void main(String []args){ 
    int i = 1024; 
    long j = i; 
    long k = i*i*i*i; 
    System.out.println("j= " +j+ ", k= " +k); 
} 

Vì vậy, khi in j, nó chỉ đơn giản đưa ra một sản lượng 1024. Nhưng trong khi in k, nó cho thấy một tràn (k = 0). Tôi đã giải quyết vấn đề này bằng cách sử dụng kỹ thuật này, nơi tôi đã đúc một cách rõ ràng mỗi i đến long. ví dụ:

public static void main(String []args){ 
    int i = 1024; 
    long j = i; 
    long k = ((long)i)*((long)i)*((long)i)*((long)i); 
    System.out.println("j= " +j+ ", k= " +k); 
} 

Bây giờ, nó đã cho thấy giá trị đúng của cả hai jk. Vì vậy, tôi muốn biết lý do tại sao điều này cần thiết để đúc int trong trường hợp thứ hai nhưng không phải trong trường hợp đầu tiên. k, là long có thể giữ lại giá trị này sau lần gán nặng này. Nhưng, tại sao nó không được chỉ định một cách chính xác?

+0

truyền đầu tiên 'i' đến đủ phải đủ –

+0

((dài) i) * i * i * i –

+4

Mẫu bị lỗi mà bạn đã xác định - một phép nhân số nguyên có thể tràn mà được chuyển đổi" quá muộn "đến một loại lớn hơn - tương đối phổ biến ở cả C# và Java; chúng tôi tìm thấy hơn năm trường hợp trên một triệu dòng mã được phân tích. Một khiếm khuyết có liên quan với tỷ lệ khám phá tương tự là một bộ phận của hai số nguyên và một chuyển đổi "quá trễ" thành một đôi; mọi người thường ngạc nhiên rằng ba trăm chia cho năm trăm và được gán cho một đôi là bằng không, không phải 0,6. –

Trả lời

19

Lý do là dòng bạn

long k = i*i*i*i; 

có thể được coi như

long k = ((i*i)*i)*i; 

hoặc ...

int k1 = i*i; 
int k2 = k1*i; 
int k3 = k2*i; 
long k = k3; 

Vì vậy, khi bất kỳ kn tràn, bạn sẽ có được lỗi.

Khi bạn thực hiện nhiệm vụ của mình, bạn rõ ràng đang phá vỡ vấn đề này bằng cách luôn nhân long s với nhau.

Tất nhiên, sửa đổi đơn giản nhất đối với chương trình ban đầu của bạn là xác định ilong ngay lập tức, thay vì int.

long i = 1024L; 
+0

@dav_i, 'k3' sẽ bị tràn vì đó là biến' int', phải là 'long' – MajidTaheri

6

i*i*i*i là một phép nhân int, vì vậy kết quả là số nguyên chỉ (trường hợp này tràn trong trường hợp của bạn). cho một kết quả lâu bạn chỉ cần phải chuyển đổi một trong số họ để dài vì vậy đây là đủ

long k = ((long)i)*i*i*i; 
+0

Tính tương thích có được phát ở đây không? Tôi có nghĩa là, nếu nó là đúng liên kết, sau đó, nếu nó vượt qua integer_max_value trước đây trước khi đến (dài i), nó sẽ hiển thị một tràn một lần nữa trong trường hợp của bạn. –

+0

thử nó @ShashishChandra – Sanjeev

+1

Tôi đã thử nó, và cảm ơn bạn, nó đã làm việc. Tôi vừa hỏi, liệu có bất kỳ vai trò kết hợp nào ở đây không? –

2

Trong lần đầu tiên giá trị của i là một int và multipllication số nguyên xảy ra và i*i*i*i kết quả là số nguyên và do đó integer overflow.

Trường hợp như trong trường hợp thứ hai bạn đang nói rõ ràng/đưa ra kết quả là long.

+0

Cảm ơn bạn đã trả lời. Nó thực sự hữu ích. Cảm kích điều đó. –

2

1099511627776 mà là kết quả của phép nhân là >Integer.MAX_VALUE vì nó là Integer Phép nhân nên sau khi i*i*i giá trị sẽ là 1073741824 nhưng sau khi nhân với 1024 nó trở nên ra khỏi phạm vi gây integer overflow và k sẽ là 0.

  • Bạn có thể đúc một trong những i-long
  • Multiply với 1L (1L*i*i*i*i) Nhưng KHÔNG i*i*i*i*1L
  • Bạn cũng có thể gán i*i*i dài và hơn nhân với i như thế này long k =(k=i*i*i)*i;
+1

Cảm ơn bạn đã trả lời. Tôi đánh giá cao nó. –

7

Vấn đề này được dựa trên thực tế là các loại khác nhau sử dụng số lượng bộ nhớ khác nhau. int và long đều là Số nguyên, sự khác biệt là int là 4 byte, trong khi dài là 8 byte.

Cho phép sửa đổi mã của bạn một chút:

public class Test { 


    public static void main(String []args){ 
     int i = 1024; 
     long j = i; 
     long k = i*i*i; 

     System.out.println("My multipliers are of type int:"); 
     System.out.println("j= " +j+ ", k= " +k);   
     System.out.println("Is k less than Integer.MAX_VALUE: " + (k < Integer.MAX_VALUE? "YES" : "NO")); 
     k = i*i*i*i; 
     System.out.println("j= " +j+ ", k= " +k); 

     //now multiplying with j instead of i 
     System.out.println("\nNow Im working with a long type:"); 
     k = j*j*j; 
     System.out.println("j= " +j+ ", k= " +k);   
     System.out.println("Is k less than Integer.MAX_VALUE: " + (k < Integer.MAX_VALUE? "YES" : "NO")); 
     k = j*j*j*j; 
     System.out.println("j= " +j+ ", k= " +k); 
     System.out.println("Is k less than Integer.MAX_VALUE: " + (k < Integer.MAX_VALUE? "YES" : "NO")); 
     k = j*j*j*j; 

    } 

} 

Đoạn mã trên cho thấy rằng khi bạn đã nhân với tôi 3 lần kết quả là một giá trị nhỏ hơn Integer.MAX_VALUE (đó là 2147483647), và khi bạn nhân nó 4 lần kết quả là 0 vì không có đủ chỗ trong 4 byte nghèo của các số nhân. :) Nhưng bạn có thể thấy rằng khi các số nhân (bên phải, j) có kiểu dài, giá trị chính xác được in và lần in cuối cùng cho thấy rằng câu lệnh k < Integer.MAX_VALUE là sai, đó là lý do cho bạn số không. :)

+0

Cảm ơn bạn đã trả lời. Tôi đánh giá cao nó. –

Các vấn đề liên quan