2012-04-09 35 views
20

Nếu tôi đang làm việc với một số double và tôi chuyển đổi nó thành một float, cách thức hoạt động chính xác? Liệu giá trị có bị cắt ngắn để nó vừa với một phao không? Hay giá trị có được làm tròn khác nhau? Xin lỗi nếu điều này nghe có vẻ hơi khắc phục, nhưng tôi đang cố nắm bắt khái niệm về các chuyển đổi floatdouble.Chuyển đổi từ kép thành float trong Java

+0

http://stackoverflow.com/a/2781125/986169 – giorashc

Trả lời

19

Từ Java Language Specification, section 5.1.3:

Chuyển đổi nguyên thủy thu hẹp từ đôi nổi được điều chỉnh bởi IEEE 754 quy tắc làm tròn (§4.2.4). Chuyển đổi này có thể mất độ chính xác, nhưng cũng mất phạm vi, dẫn đến một số không bằng 0 từ một nonzero đôi và một vô cực nổi từ một đôi hữu hạn. Một NaN kép được chuyển đổi thành một NaN dạng float và một vô cực kép được chuyển đổi thành vô cực float cùng ký.

section 4.2.4 nói:

Các ngôn ngữ lập trình Java đòi hỏi dấu chấm động số học cư xử như thể mỗi nhà khai thác dấu chấm tròn kết quả dấu chấm động của nó đến độ chính xác kết quả. Kết quả không chính xác phải được làm tròn đến giá trị thể hiện gần nhất với kết quả vô cùng chính xác; nếu hai giá trị gần nhất có thể biểu diễn bằng nhau, thì giá trị nhỏ nhất có nghĩa là bit zero được chọn. Đây là chế độ làm tròn mặc định của chuẩn IEEE 754 được gọi là vòng tròn gần nhất.

+0

Cảm ơn vì điều này. Tôi nhận thấy rằng nó đề cập đến việc sử dụng vòng IEEE 754 gần nhất. Có anyway để chỉ định một chế độ làm tròn khác nhau? – Franklin

+0

@Franklin: Có lớp ['RoundingMode'] (http://docs.oracle.com/javase/7/docs/api/java/math/RoundingMode.html), nhưng tôi nghĩ rằng chỉ áp dụng cho' BigDecimal' và 'BigInteger' hoạt động, không hoạt động trên nguyên thủy. Nhưng tôi không tin tưởng 100% vào điều đó. –

+1

Java chỉ hỗ trợ một chế độ làm tròn fp - đã có một số cuộc nói chuyện về cách thêm nhiều năm trước (chủ yếu cho cộng đồng HPC; tức là về xử lý các ký hiệu, vv), nhưng than ôi không đi đâu cả. – Voo

8

Tôi cho rằng các loại dấu phẩy động được coi là đại diện cho nhiều dãy giá trị. Lý do 0.1f hiển thị dưới dạng 0,1 thay vì 0.100000001490116119384765625 là nó thực sự đại diện cho phạm vi số từ 13421772.5/134217728 đến 13421773.5/134217728 (tức là từ 0.0999999977648258209228515625 đến 0,1000000052154064178466796875); nó sẽ không có ý nghĩa để thêm chữ số phụ cho thấy số lượng lớn hơn 0.100 khi nó có thể ít hơn, và cũng không sử dụng một chuỗi các số chỉ ra số lượng nhỏ hơn 0.100 khi nó có thể lớn hơn.

Việc tạo nhân đôi thành phao sẽ chọn phao có phạm vi giá trị bao gồm phạm vi số đôi được biểu thị bằng số double. Lưu ý rằng trong khi thao tác này không thể đảo ngược, kết quả của phép toán nói chung sẽ chính xác về mặt số học; thời gian duy nhất nó sẽ không được 100% số học chính xác sẽ là nếu một người được đúc để nổi một đôi có phạm vi được chính xác tập trung vào ranh giới giữa hai phao. Trong tình huống đó, hệ thống sẽ chọn phao ở một bên hoặc bên kia của dải kép; nếu số thực tế gấp đôi đại diện cho một số ở bên trái của phạm vi, kết quả chuyển đổi sẽ hơi không chính xác.

Thực tế, sự thiếu chính xác nêu trên hầu như không bao giờ có liên quan, bởi vì "phạm vi giá trị" được biểu thị bằng loại dấu phẩy động thực tế lớn hơn một chút so với chỉ dẫn ở trên. Việc tính toán (chẳng hạn như bổ sung) trên hai số có một số lượng không chắc chắn sẽ mang lại kết quả với độ không chắc chắn hơn, nhưng hệ thống sẽ không theo dõi được mức độ không chắc chắn tồn tại. Tuy nhiên, trừ khi một thực hiện hàng chục hoạt động trên một phao, hoặc hàng ngàn hoạt động trên một đôi, số lượng không chắc chắn sẽ thường là đủ nhỏ không phải lo lắng về. Điều quan trọng cần lưu ý là việc đúc một phao lên gấp đôi thực sự là hoạt động nguy hiểm hơn nhiều so với việc đúc gấp đôi để nổi, ngay cả khi Java cho phép ẩn hoàn toàn trước đó mà không có cảnh báo nhưng squawks ở phía sau. Việc đưa một phao vào một hệ đôi sẽ làm cho hệ thống lựa chọn vùng có dải ô được căn giữa về tâm của phạm vi float. Điều này hầu như luôn dẫn đến một giá trị có độ không đảm bảo thực sự lớn hơn nhiều so với giá trị điển hình của các con số có độ chính xác gấp đôi. Ví dụ, nếu một phôi 0.1f để tăng gấp đôi, kết quả đôi sẽ đại diện cho một số trong phạm vi 0.10000000149011611 đến 0.10000000149011613, mặc dù số lượng nó được cho là đại diện (một phần mười) là, tương đối nói, không nơi nào gần phạm vi đó.

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