2008-11-22 18 views
240

Theo tài liệu, phương pháp decimal.Round sử dụng thuật toán tròn tới thậm chí không phổ biến đối với hầu hết các ứng dụng. Vì vậy, tôi luôn kết thúc bằng cách viết một hàm tùy chỉnh để thực hiện thuật toán nửa vòng tự nhiên hơn:Tại sao .NET sử dụng làm tròn của ngân hàng làm mặc định?

public static decimal RoundHalfUp(this decimal d, int decimals) 
{ 
    if (decimals < 0) 
    { 
     throw new ArgumentException("The decimals must be non-negative", 
      "decimals"); 
    } 

    decimal multiplier = (decimal)Math.Pow(10, decimals); 
    decimal number = d * multiplier; 

    if (decimal.Truncate(number) < number) 
    { 
     number += 0.5m; 
    } 
    return decimal.Round(number)/multiplier; 
} 

Có ai biết lý do đằng sau quyết định thiết kế khung này không?

Có bất kỳ triển khai tích hợp nào của thuật toán nửa vòng vào khung không? Hoặc có thể một số API Windows không được quản lý?

Nó có thể gây hiểu lầm cho người mới bắt đầu chỉ đơn giản là viết decimal.Round(2.5m, 0) mong 3 là kết quả nhưng nhận được 2 thay thế.

+93

Làm tròn không phải là "tự nhiên hơn". Thiên nhiên không liên quan gì đến nó cả. Nó chỉ đơn giản là những gì bạn đã học được ở lớp mẫu giáo khi bạn học được khái niệm "làm tròn". Các bài học ở cấp lớp không phải lúc nào cũng vẽ một bức tranh đầy đủ. –

+37

@Rob Và đó là lý do tại sao nó tự nhiên hơn **, mặc dù nó không đúng * – Pacerier

+10

Tôi không hiểu, @Pacerier. Tôi giải thích lý do tại sao nó không * tự nhiên, và bạn nói đó là thực tế tại sao nó * là * tự nhiên. Lập luận của tôi làm việc như thế nào * chống lại * kết luận của tôi, điều đó ngược lại với kết luận của bạn? Những điều bạn đã quen với việc có thể * cảm thấy * tự nhiên, và đôi khi chúng ta có thể nói rằng một cái gì đó là "bản chất thứ hai", nhưng điều đó không làm cho chúng trở nên tự nhiên. –

Trả lời

177

Có lẽ vì đó là thuật toán tốt hơn. Trong quá trình thực hiện nhiều vòng, bạn sẽ trung bình ra rằng tất cả .5 cuối cùng làm tròn bằng nhau lên và xuống. Điều này cho phép ước lượng tốt hơn các kết quả thực tế nếu bạn là ví dụ, thêm một loạt các số được làm tròn. Tôi sẽ nói rằng mặc dù nó không phải là điều mà một số người có thể mong đợi, nhưng đó có lẽ là điều chính xác hơn để làm.

+64

giả định rằng bạn có phân phối phẳng các đầu vào lẻ ​​và thậm chí là tất nhiên –

+6

+1 cho * thuật toán tốt hơn *, mặc dù Ostemar có câu trả lời * thực tế * (http://stackoverflow.com/questions/311696/why-does-net- sử dụng ngân hàng-làm tròn-theo-mặc định/6562018 # 6562018) –

+2

@Tôi cũng có thể trả lời +1 đó. Dù sao chúng ta có thể nhận được "câu trả lời được chấp nhận di chuyển" Có lẽ OP có thể làm điều này. Câu trả lời thực tế cho "tại sao" nó sử dụng phương pháp này là một nửa xuống trang. Mặc dù tôi khá thích việc tăng cường đại diện tôi nhận được khoảng một lần một tuần từ câu trả lời này. – Kibbee

82

Mặc dù tôi không thể trả lời câu hỏi "Tại sao các nhà thiết kế của Microsoft lại chọn tùy chọn này làm mặc định?", Tôi chỉ muốn chỉ ra rằng một chức năng bổ sung là không cần thiết.

Math.Round phép bạn chỉ định một MidpointRounding:

  • ToEven - Khi một số nằm giữa hai người khác, nó được làm tròn về phía số chẵn gần nhất.
  • AwayFromZero - Khi một số nằm giữa hai số khác, số này được làm tròn về số gần nhất cách xa số không.
+6

Và như tôi đã đề cập trong các chủ đề liên quan, hãy chắc chắn rằng bạn nhất quán trong làm tròn của bạn - nếu bạn đôi khi làm tròn trong cơ sở dữ liệu, và đôi khi trong .net, bạn sẽ có lạ, một xu lỗi sẽ đưa bạn tuần để tìm ra. – chris

+53

Một khách hàng đã thanh toán cho tôi hơn 40.000 đô la để theo dõi một lỗi làm tròn 0,11 đô la giữa hai con số mà cả hai đều chỉ nhút nhát 1 tỷ đô la; $ 0,11 là do sự khác biệt trong lỗi làm tròn chữ số 8 giữa máy tính lớn và Máy chủ SQL. Nói về một người cầu toàn! –

+9

@EJB - tôi có thể là một người cầu toàn nếu tôi đang xử lý một tỷ đô la ;-) – seanxe

23

Số thập phân được sử dụng chủ yếu cho tiền; làm tròn của ngân hàng là phổ biến khi làm việc với tiền. Hoặc bạn có thể nói.

Chủ yếu là các chủ ngân hàng cần loại số thập phân ; do đó nó “của ngân hàng làm tròn”

ngân hàng làm tròn có ưu điểm là trên trung bình bạn sẽ nhận được kết quả tương tự nếu bạn:

  • vòng một bộ “đường hóa đơn” trước khi thêm chúng lên,
  • hoặc thêm chúng lên rồi vòng tổng

làm tròn trước khi thêm lên lưu rất nhiều công việc trong những ngày trước khi máy tính.

(Trong Vương quốc Anh khi chúng tôi đi ngân hàng thập phân sẽ không đối phó với một nửa xu, nhưng trong nhiều năm đã có vẫn còn là một xu tiền xu và mua sắm thường có giá kết thúc bằng một nửa pence nửa - vì vậy rất nhiều làm tròn)

+5

"Số thập phân chủ yếu được sử dụng cho tiền" ... và mọi thứ khác không phải là số nguyên. –

+1

@JohnTyree, Không đúng phần lớn thời gian một đôi/phao được sử dụng khi nó không phải là số nguyên. xem http: // stackoverflow.com/questions/2545567/in-net-how-do-i-chọn-between-a-decimal-and-a-double –

+1

Chà. Lỗi lầm vô lý về phía tôi. 'Decmial's, vâng. Số thập phân, không. Đối với hậu thế, tôi đồng ý với tình cảm ban đầu ở đây. –

395

Các câu trả lời khác với lý do tại sao thuật toán của Ngân hàng (aka round half to even) là một lựa chọn tốt là khá chính xác. Nó không bị thiên vị tiêu cực hoặc tích cực nhiều như phương pháp round half away from zero trên hầu hết các bản phân phối hợp lý.

Nhưng câu hỏi là tại sao .NET sử dụng làm tròn thực tế của Ngân hàng làm mặc định - và câu trả lời là Microsoft đã tuân theo tiêu chuẩn IEEE 754. Điều này cũng được đề cập trong MSDN for Math.Round dưới Nhận xét.

Cũng lưu ý rằng .NET hỗ trợ phương thức thay thế được chỉ định bởi IEEE bằng cách cung cấp thông số MidpointRounding. Họ có thể tất nhiên đã cung cấp more alternatives để giải quyết các mối quan hệ, nhưng họ chọn để hoàn thành tiêu chuẩn IEEE.

+11

Vì vậy, tại sao IEEE 754 làm theo các ngân hàng làm tròn? Câu trả lời này (vẫn tốt) chỉ cần vượt qua cái xô. –

+3

@HenkHolterman Có lẽ do những gì được đề cập trong các câu trả lời khác (và khi tôi tóm tắt); nó không bị (quá nhiều) từ thiên vị tiêu cực hay tích cực và như vậy làm cho một mặc định cộng hưởng hơn cho hầu hết các bản phân phối và lĩnh vực vấn đề. – Ostemar

+1

Liên quan: [Mathematica.SE: Tại sao tròn đến số nguyên?] (Http://mathematica.stackexchange.com/questions/2116/why-round-to-even-integers) – Stijn

0

Sử dụng một quá tải chức năng Round như thế này:

decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero) 

Nó sẽ ra . Và nếu bạn sử dụng

decimal.Round(2.5m, 0,MidpointRounding.ToEven) 

bạn sẽ nhận được làm tròn của ngân hàng.

+1

Điều này không trả lời câu hỏi * tại sao * Làm tròn ngân hàng được chọn làm mặc định. – shortstuffsushi

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