2010-02-13 38 views
10

xem xét mã này:Tại sao loại kết quả của một phân chia các số nguyên ngắn trong Java không phải là một số nguyên ngắn?

public class ShortDivision { 
    public static void main(String[] args) { 
     short i = 2; 
     short j = 1; 
     short k = i/j; 
    } 
} 

Biên dịch này tạo ra các lỗi

ShortDivision.java:5: possible loss of precision 
found : int 
required: short 
     short k = i/j; 

vì kiểu của biểu thức i/j được rõ ràng int, và do đó phải được đúc để ngắn.

Tại sao loại i/j không ngắn?

+1

Vì việc chuyển đổi một đoạn ngắn thành một đoạn ngắn sẽ làm mất độ chính xác. (-32768/-1) –

Trả lời

16

Từ Java spec:

5.6.2 Binary Numeric Xúc tiến

Khi một nhà điều hành áp dụng chương trình khuyến mãi số nhị phân sang một cặp toán hạng, mỗi trong số đó phải biểu thị một giá trị của một loại số, áp dụng các quy tắc sau, theo thứ tự, sử dụng chuyển đổi mở rộng (§5.1.2) để chuyển đổi toán hạng khi cần:

Nếu toán hạng là loại gấp đôi, toán hạng còn lại được chuyển thành gấp đôi.

Nếu không, nếu toán hạng là loại phao, thì toán hạng còn lại được chuyển thành phao.

Nếu không, nếu toán hạng là loại dài, cột kia được chuyển đổi thành dài.

Nếu không, cả hai toán hạng sẽ được chuyển thành loại int.

Đối với hoạt động nhị phân, các loại số nguyên nhỏ được thăng int và kết quả của các hoạt động là int.


EDIT: Tại sao lại như vậy? Câu trả lời ngắn gọn là Java đã sao chép hành vi này từ C. Một câu trả lời dài hơn có thể liên quan đến thực tế là tất cả các máy hiện đại đều làm ít nhất 32 bit tính toán, và thực sự khó khăn hơn đối với một số máy làm 8 bit và Hoạt động 16 bit.

Xem thêm: OR-ing bytes in C# gives int

+0

thêm: Khuyến mãi số nhị phân được thực hiện trên toán hạng của một số toán tử nhất định: - Toán tử nhân *,/và% – akf

+0

OK, tôi hiểu rằng đặc tả ngôn ngữ nói rằng ngôn ngữ sẽ hoạt động như thế này (nếu không trình biên dịch sẽ không tạo ra lỗi ở nơi đầu tiên). Nhưng tôi không hiểu động cơ đằng sau nó. Tại sao họ quảng cáo các loại trước khi thực hiện phân chia thay vì chỉ chia quần short? – flodin

+0

Đặt cược của tôi là "thats the way it in C". Java được thiết kế để thu hút các lập trình viên C++ - đòi hỏi mọi thứ phải giống nhau –

2

Về động lực: cho phép tưởng tượng thay thế cho hành vi này và xem tại sao họ không làm việc:

Alternative 1: kết quả nên luôn luôn giống như các đầu vào .

Kết quả sẽ là gì khi thêm int và ngắn?

Kết quả là gì để nhân hai quần short? Kết quả nói chung sẽ phù hợp với một int, nhưng bởi vì chúng tôi cắt ngắn để ngắn, hầu hết các phép nhân sẽ không âm thầm. Truyền tới một int sau đó sẽ không giúp ích gì.

Phương án 2: kết quả luôn là loại nhỏ nhất có thể đại diện cho tất cả các kết quả đầu ra có thể.

Nếu loại trả về là ngắn, câu trả lời sẽ không phải lúc nào cũng thể hiện được.

Một giá trị ngắn có thể chứa -32,768 đến 32,767. Sau đó, kết quả này sẽ gây ra tràn:

short result = -32768/-1; // 32768: not a short 

Vì vậy, câu hỏi của bạn sẽ trở thành: tại sao thêm hai int không trả lại lâu? Nhân của hai int là gì? Dọc theo? Một BigNumber để bao gồm trường hợp của giá trị số nguyên min bình phương?

Cách 3: Chọn điều hầu hết mọi người có thể muốn phần lớn thời gian

Vì vậy, kết quả nên là:

  • int cho nhân hai quần short, hoặc bất kỳ int hoạt động.
  • ngắn nếu thêm hoặc trừ quần short, phân chia ngắn theo bất kỳ loại số nguyên nào, nhân hai byte, ...
  • byte nếu bithifting byte sang phải, int nếu bitshifting sang trái.
  • etc ...

Nhớ tất cả các trường hợp đặc biệt sẽ khó nếu không có logic cơ bản cho chúng. Nó đơn giản hơn để chỉ nói: kết quả của các hoạt động số nguyên luôn luôn là một int.

+0

Những gì mọi người muốn, không phải lúc nào cũng giống như ý tưởng hay nếu bạn thiết kế lại nó. Một ví dụ điển hình là sắp xếp bàn phím QWERTY. Ban đầu được thiết kế để * làm chậm * typists để máy đánh chữ sẽ không bị kẹt. Tuy nhiên, tôi không thể tưởng tượng bằng cách sử dụng bất cứ điều gì khác như tôi đã quen với nó. –

+0

@Peter Lawrey: Đúng vậy. Nếu Henry Ford hỏi mọi người về loại xe anh ta nên sản xuất, nhiều người sẽ yêu cầu một chiếc xe với ** 6 ** con ngựa thay vì 4. Lắng nghe những gì người dùng của bạn muốn là một điều tốt, nhưng đôi khi bạn cần phải cung cấp chúng có cái gì đó khác với những gì họ muốn bởi vì họ thậm chí không thể tưởng tượng ra một giải pháp khác so với những gì họ thường làm. –

+0

Đối với các ngôn ngữ không có quá tải toán tử, tại sao không có kết quả nhỏ hơn (kết quả lớn nhất có thể) hoặc (kích thước của vùng chứa nhận)? Trong hầu hết các trường hợp, quy tắc như vậy sẽ mang lại mã nhỏ hoặc nhỏ hơn bất kỳ thứ gì có thể được biểu thị để mang lại kết quả chính xác theo số học bằng cách sử dụng phương pháp # 1. Ví dụ, nếu các biến là 32 bit, 'p = (x * y)/z;' sẽ thực hiện phân chia 32x32-> 64 nhân và 64/32-> 32. Nếu 'p' và' z' là 16 bit, nó sẽ thực hiện nhân 32x32-> 64, giảm 64-> 32, và phân chia 32/16-> 16. – supercat

0

Nó chỉ là một lựa chọn thiết kế để phù hợp với C/C++ đã thống trị ngôn ngữ khi Java được thiết kế.

Ví dụ: i * j có thể được triển khai để loại được quảng bá từ byte => short, short => int và int => long và điều này sẽ tránh tràn nhưng không. (Nó có trong một số ngôn ngữ) Đúc có thể được sử dụng nếu hành vi hiện tại được mong muốn, nhưng sự mất mát của một số bit sẽ được rõ ràng.

Tương tự, i/j có thể được nhắc từ byte/short => float hoặc int/long => double.

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