2010-04-07 26 views
5

Tôi có một tính mà tạo ra những gì dường như là phao 22,23, và một chữ 22,23 như vậy:Tại sao Ruby không bình đẳng trên 2 phao xuất hiện giống nhau?

some_object.total => 22.23 
some_object.total.class => Float 

22.23 => 22.23 
22.23.class => Float 

Nhưng đối với một số lý do, sau đây là sai:

some_object.total == 22.23 ? true : false 

Wacky, phải ?

Có một số loại cơ chế chính xác nào được sử dụng có thể không hoàn toàn minh bạch thông qua cuộc gọi some_object.total?

+0

gì phiên bản của Ruby? 1.8.6 có một số lỗi số học nổi. – mckeed

+0

Xin chào, bạn cũng có thể kiểm tra bài đăng của tôi về các vấn đề điểm nổi http://vladzloteanu.wordpress.com/2010/01/11/why-you-shouldnt-use-float-for-currency-floating-point-issues-explained -for-ruby-and-ror/ –

Trả lời

9

Số dấu chấm động không thể đại diện chính xác tất cả các số thập phân trong phạm vi của chúng. Ví dụ, 0,9 không chính xác 0,9, đó là một con số thực sự gần 0,9 mà gió lên được in như nó trong nhiều trường hợp. Khi bạn thực hiện các phép tính dấu chấm động, các lỗi này có thể tích luỹ và bạn kết thúc với một thứ rất gần đúng số nhưng không chính xác bằng nó. Ví dụ: 0.3 * 3 == 0.9 sẽ trả lại false. Đây là trường hợp trong mọi ngôn ngữ máy tính mà bạn từng sử dụng - đó chỉ là cách toán nhị phân dấu chấm động hoạt động. Xem, ví dụ: this question about Haskell.

Để kiểm tra tính bình đẳng dấu phẩy động, bạn thường muốn kiểm tra xem số có nằm trong phạm vi nhỏ nhất của mục tiêu hay không. Vì vậy, ví dụ:

def float_equal(a, b) 
    if a + 0.00001 > b and a - 0.00001 < b 
    true 
    else 
    false 
    end 
end 

Bạn cũng có thể sử dụng lớp BigDecimal trong Ruby để biểu thị số thập phân tùy ý.

Nếu đây là một trường hợp kiểm tra, bạn có thể sử dụng assert_in_delta:

def test_some_object_total_is_calculated_correctly 
    assert_in_delta 22.23, some_object.total, 0.01 
end 
+0

Yup, điều đó sẽ giúp bạn! Cảm ơn! – btelles

+2

Chỉ cần để làm cho rõ ràng nếu nó không phải là từ bài của Chuck, đây không phải là một giới hạn điểm nổi ruby. Đây là một điểm giới hạn dấu chấm động. Nó hoạt động theo cách này trong mọi ngôn ngữ sử dụng điểm nổi IEEE. Các vấn đề về số là một chủ đề quan trọng và hơi sâu mà bạn sẽ đề cập ở một số điểm trong bất kỳ chương trình giảng dạy khoa học máy tính nào. – frankc

+0

Cảm ơn bro. Phương thức assert_in_delta đã làm cho tôi. Tôi đã nhận được: "<3375.0> dự kiến ​​nhưng là <3375.0>" và không hiểu những gì đang diễn ra! – mjnissim

1

có điều gì đó đang diễn ra tại đây. đây là từ 1.8.7 irb

irb(main):001:0> class Test 
irb(main):002:1> attr_accessor :thing 
irb(main):003:1> end 
=> nil 
irb(main):004:0> t = Test.new 
=> #<Test:0x480ab78> 
irb(main):005:0> t.thing = 22.5 
=> 22.5 
irb(main):006:0> t.thing == 22.5 
=> true 
+0

tổng số thực sự là một tổng và tính toán của một số số khác, gây ra những thiếu chính xác. – btelles

6

Float#to_sFloat#inspect vòng. Hãy thử "%.30f" % some_object.total và bạn sẽ thấy rằng nó không hoàn toàn 22.23.

+0

heh ... "22.229999999999996873611962655559" Đúng vậy. Cảm ơn. – btelles

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