Bộ phận nguyên: Làm thế nào để bạn sản xuất một đôi?


249

Đối với khối mã này:

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

giá trị của d0.0 . Nó có thể bị buộc phải làm việc bằng cách đúc:

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

Nhưng có một cách khác để có được doublekết quả chính xác ? Tôi không thích đúc nguyên thủy, ai biết điều gì có thể xảy ra.



9
truyền một 'int' thành gấp đôi là an toàn, bạn sẽ luôn nhận được cùng một giá trị mà không mất độ chính xác.
Peter Lawrey

1
Tôi muốn biết nếu sau đây là các bước chính xác được trình biên dịch thực hiện cho phép chia: 1) cast num to float 2) cast denom to float as 2) chia num cho denom. Xin vui lòng cho tôi biết nếu tôi không chính xác.
mannyee

Câu trả lời:


156
double num = 5;

Điều đó tránh một diễn viên. Nhưng bạn sẽ thấy rằng các chuyển đổi diễn viên được xác định rõ. Bạn không cần phải đoán, chỉ cần kiểm tra JLS . int to double là một chuyển đổi mở rộng. Từ §5.1.2 :

Mở rộng chuyển đổi nguyên thủy không làm mất thông tin về cường độ tổng thể của một giá trị số.

[...]

Chuyển đổi giá trị int hoặc giá trị dài thành float hoặc giá trị dài thành gấp đôi, có thể dẫn đến mất độ chính xác - nghĩa là, kết quả có thể mất một số bit có giá trị nhỏ nhất. Trong trường hợp này, giá trị dấu phẩy động thu được sẽ là phiên bản được làm tròn chính xác của giá trị số nguyên, sử dụng chế độ làm tròn từ tròn đến gần nhất của IEEE 754 (§4.2.4) .

5 có thể được thể hiện chính xác như là một đôi.


60
+1. Ngừng sợ đúc. Tìm hiểu làm thế nào nó hoạt động. Tất cả đều được xác định rõ ràng.
Mark Peters

1
@FovenioPH Điều này hoạt động trong mọi tình huống và giống hệt với giải pháp * 1.0.
Vitruvius

3
@Saposhiente Nó vượt ra ngoài làm việc hay không. Thay đổi loại biến có vẻ như mã bẩn đối với tôi. Nếu bạn có một cái gì đó PHẢI là một số nguyên và bạn thay đổi biểu diễn cho một số float chỉ để có thể thực hiện phép toán, bạn có thể gặp rủi ro cho chính mình. Ngoài ra trong một số ngữ cảnh đọc biến dưới dạng một số nguyên làm cho mã dễ hiểu hơn.
Fabricio PH

2
@FovenioPH, nhân với 1.0vẫn thay đổi loại kết quả, chỉ theo một cách khác. "Có vẻ như mã bẩn đối với tôi" không giải thích trong trường hợp nào bạn tin rằng nhân với 1.0thực sự tốt hơn (hoặc tại sao điều đó có thể xảy ra).
Matthew Flaschen

4
@FovenioPH Bạn và OP dường như đang lao động theo niềm tin sai lầm (nơi bạn nói "Thay đổi loại biến") làm (double)numthay đổi bằng cách nào đó num. Nó không - nó tạo ra một gấp đôi tạm thời cho bối cảnh của tuyên bố.
Paul Tomblin

100

Có gì sai khi đúc nguyên thủy?

Nếu bạn không muốn chọn vì một số lý do, bạn có thể làm

double d = num * 1.0 / denom;

63
... đó là một diễn viên ngầm trước khi nhân
Alice Purcell

2
Trong hầu hết các trường hợp, điều này tốt hơn là thay đổi loại biến khác.
Fabricio PH

3
@FovenioPH Không có gì cho thấy điều này là đúng, trừ khi bạn có một nguồn để trích dẫn.
Vitruvius

1
@Saposhiente đã trả lời trong nhận xét tương tự khác của bạn
Fabricio PH

1
Bạn cũng có thể sử dụng hậu tố "D" (để thực hiện cùng một biểu mẫu ẩn); - ví dụ:double d = num * 1D / denom;
BrainSlugs83

73

Tôi không thích đúc nguyên thủy, ai biết điều gì có thể xảy ra.

Tại sao bạn có một nỗi sợ phi lý về việc đúc nguyên thủy? Không có gì xấu sẽ xảy ra khi bạn cast một intđến một double. Nếu bạn không chắc chắn về cách thức hoạt động của nó, hãy tìm nó trong Đặc tả ngôn ngữ Java . Đúc một intđến doublelà một chuyển đổi nguyên thủy mở rộng .

Bạn có thể loại bỏ cặp dấu ngoặc đơn thừa bằng cách sử dụng mẫu số thay vì tử số:

double d = num / (double) denom;

2
bạn cũng có thể làm double d = (double) num / denom;... (OK, cái này phụ thuộc vào quyền ưu tiên)
user85421

27

Nếu bạn thay đổi loại của một biến, bạn phải nhớ quay lại gấp đôi nếu công thức của bạn thay đổi, bởi vì nếu biến này dừng là một phần của phép tính, kết quả sẽ bị rối. Tôi tạo thói quen truyền trong phép tính và thêm nhận xét bên cạnh.

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

Lưu ý rằng việc truyền kết quả sẽ không làm điều đó

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

17

Truyền một trong các số nguyên / cả hai số nguyên để thả nổi để buộc phép toán được thực hiện với phép toán dấu phẩy động. Mặt khác, toán học số nguyên luôn được ưu tiên. Vì thế:

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

Lưu ý rằng việc đúc kết quả sẽ không làm điều đó. Bởi vì phân chia đầu tiên được thực hiện theo quy tắc ưu tiên.

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

Tôi không nghĩ rằng có bất kỳ vấn đề nào với việc phân vai như bạn đang nghĩ.


10

Kiểu đúc là cách duy nhất


Tạo một doublephân chia từ số nguyên - không có cách nào khác mà không truyền (có thể bạn sẽ không làm điều đó một cách rõ ràng nhưng nó sẽ xảy ra).

Bây giờ, có một số cách chúng ta có thể cố gắng để có được doublegiá trị chính xác (nơi numdenomintloại, và tất nhiên với việc đúc ) -

  1. với đúc rõ ràng:

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

nhưng không double d = (double) (num / denom);

  1. với đúc ngầm:

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

nhưng không double d = num / denom * 1.0;
và khôngdouble d = 0.0 + ( num / denom );


2

sử dụng một cái gì đó như:

double step = 1d / 5;

(1d là gấp đôi)


5
1d không phải là diễn viên, nó chỉ là một tuyên bố.
Sefier Tang

0

Bạn có thể xem xét gói các hoạt động. Ví dụ:

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

Điều này cho phép bạn tra cứu (chỉ một lần) xem diễn viên có làm đúng những gì bạn muốn hay không. Phương pháp này cũng có thể phải chịu các thử nghiệm, để đảm bảo rằng nó tiếp tục làm những gì bạn muốn. Nó cũng không quan trọng bạn sử dụng thủ thuật gì để gây ra sự phân chia (bạn có thể sử dụng bất kỳ câu trả lời nào ở đây), miễn là nó mang lại kết quả chính xác. Bất cứ nơi nào bạn cần chia hai số nguyên, bây giờ bạn có thể chỉ cần gọi Utils::dividevà tin tưởng rằng nó làm đúng.


0

chỉ cần sử dụng cái này

int fxd=1;
double percent= (double)(fxd*40)/100;

0

Cách tốt nhất để làm điều này là

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

d is 3.0 now.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.