2011-11-10 40 views
5

Nguồn cho round trong commons apache trông như thế này:Tại sao chúng ta cần phải chuyển đổi đôi thành một chuỗi, trước khi chúng ta có thể chuyển đổi nó thành một BigDecimal?

public static double round(double x, int scale, int roundingMethod) { 
    try { 
     return (new java.math.BigDecimal(Double.toString(x)).setScale(scale, roundingMethod)).doubleValue(); 
    } catch (NumberFormatException ex) { 
     if (Double.isInfinite(x)) { 
      return x; 
     } else { 
      return Double.NaN; 
     } 
    } 
} 

tôi đã tự hỏi, khi tạo BigDecimal tại sao họ chọn để chuyển đổi gấp đôi lên một chuỗi (sử dụng Double.toString) thay vì chỉ đơn giản bằng cách sử dụng đôi chinh no?

Nói cách khác, có vấn đề gì với điều này? :

public static double round(double x, int scale, int roundingMethod) { 
    try { 
     return (new java.math.BigDecimal(x).setScale(scale, roundingMethod)).doubleValue(); 
    } catch (NumberFormatException ex) { 
     if (Double.isInfinite(x)) { 
      return x; 
     } else { 
      return Double.NaN; 
     } 
    } 
} 

Trả lời

7

Đó là vì kết quả của hàm xây dựng BigDecimal(double) là không thể đoán trước như được đề cập trong javadoc.

Người ta có thể giả định rằng viết BigDecimal mới (0,1) trong Java tạo ra một BigDecimal chính xác bằng 0.1 (một giá trị chưa định tỷ lệ trong tổng số 1, với tỷ lệ 1), nhưng nó thực sự là tương đương với 0,1000000000000000055511151231257827021181583404541015625

Các chuỗi nhà xây dựng, mặt khác, là hoàn toàn có thể dự đoán: viết BigDecimal mới ("0,1") tạo một BigDecimal chính xác là bằng 0,1, như mong đợi. Do đó, thường là khuyến cáo rằng hàm tạo String được sử dụng tùy chọn này là .

Test Case:

System.out.println(java.math.BigDecimal.valueOf(0.1).toString()); 
System.out.println(new java.math.BigDecimal(0.1).toString()); 
+0

@@ Cảm ơn bạn! – Pacerier

1

Bạn không phải chuyển đổi thành Chuỗi.
Sử dụng phương thức tĩnh BigDecimal.valueOf(double val):

Để sử dụng trong mã của bạn:

... 
return (BigDecimal.valueOf(x).setScale(scale, roundingMethod)).doubleValue(); 
.... 
+0

Các tài liệu đã viết rằng 'BigDecimal.valueOf (x)' tương đương với 'new java.math.BigDecimal (Double.toString (x))', vì vậy về cơ bản tôi đã tự hỏi sự khác biệt giữa 'new java.math .BigDecimal (Double.toString (x)) 'và' new java.math.BigDecimal (x) '? – Pacerier

+0

Nếu đó là cách nó được thực hiện, vì vậy hãy là nó. Điều đó có thể thay đổi trong các JDK tương lai. Tập trung vào API - việc triển khai không nên lo lắng bạn (trừ khi tất nhiên nó thực sự ảnh hưởng đến quyết định thiết kế của bạn, điều đó có thể có nghĩa là thiết kế của bạn thiếu sót theo một cách nào đó) – Bohemian

4

Từ các tài liệu here cho các nhà xây dựng BigDecimal(String val):

Lưu ý: Đối với các giá trị khác hơn float và double NaN và ± Infinity, hàm tạo này tương thích với các giá trị được trả về bởi Float.toString (float) và Double.toString (double). Điều này thường là cách ưa thích để chuyển đổi một phao hoặc tăng gấp đôi thành một BigDecimal, như nó không bị khó lường trước của phương thức khởi tạo BigDecimal (double) .

+0

Và nếu bạn thực sự muốn thấy sự khác biệt, hãy nhớ nguồn BigDecimal là có sẵn. http://www.docjar.com/html/api/java/math/BigDecimal.java.html – madth3

1

Dường như với tôi rằng chìa khóa là trong bản Tuyên Bố này:

BigDecimal (val kép)
dịch một đôi vào một BigDecimal là đại diện thập phân chính xác của nhị phân của đôi dấu chấm động giá trị.

so

BigDecimal (String val)
Dịch các chuỗi đại diện của một BigDecimal thành một BigDecimal.

Bằng cách chuyển đến chuỗi đầu tiên, bạn chỉ thấy gấp đôi là BigDecimal, nhưng nếu xây dựng trực tiếp từ đôi, bạn đang làm việc với biểu diễn mức bit và tôi sẵn sàng đặt cược bạn muốn có được một câu trả lời hoàn toàn khác biệt. Hãy nhớ rằng các giá trị dấu phẩy động được biểu diễn bằng cách sử dụng các phần của 64 bit cho toàn bộ phần và một phần cho phần phân số và một phần đại diện cho số mũ (trong cơ sở 2) - đó là tất cả các công cụ rất bí truyền, khác nhau từ máy này sang máy khác, và tôi nghĩ định nghĩa chính thức duy nhất được tìm thấy trong số Necronomicon.

Cập nhật: Điều gì Borodin cho biết.

1

Tuy nhiên, tôi tìm thấy một câu hỏi:

System.out.println(java.math.BigDecimal.valueOf(0.1000000000000000055511151231257827021181583404541015625).toString()); 

Nó sẽ in 0,1.

Tôi nghĩ khóa là java.lang.Double.toString (double d). Khi chúng tôi nhập 0.1 (Trong Java, giá trị chính xác là 0.1000000000000000055511151231257827021181583404541015625), hàm sẽ thả đuôi và chúng tôi nhận được 0.1. Tuy nhiên. nếu chúng tôi nhập 0.1000000000000000055511151231257827021181583404541015625, nó luôn luôn thả đuôi và chúng tôi cũng nhận được 0.1 là trái với mong đợi của chúng tôi.

Vì vậy, chúng ta phải nhận thức được yêu cầu của chúng tôi để lựa chọn java.math.BigDecimal.valueOf (val kép) hoặc java.math.BigDecimal.BigDecimal (val kép).

+0

yea nếu chúng tôi muốn làm việc đó, chúng tôi phải có 'new java.math.BigDecimal (" 0.1000000000000000055511151231257827021181583404541015625 ")' – Pacerier

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