2012-02-09 5 views
7

Tôi đang cố gắng thực hiện một số so sánh số và tôi nhận được một số kết quả lạ.So sánh NSNumber: trả về các kết quả khác nhau

NSNumber* number1 = [NSNumber numberWithFloat:1.004]; 
NSNumber* number2 = [NSNumber numberWithDouble:1.004]; 

([number1 compare:number2] == NSOrderedSame) ? NSLog(@"YES") : NSLog(@"NO"); 
([number1 compare:number2] == NSOrderedAscending) ? NSLog(@"YES") : NSLog(@"NO"); 
([number1 doubleValue] == [number2 doubleValue]) ? NSLog(@"YES") : NSLog(@"NO"); 
([number1 floatValue] == [number2 floatValue]) ? NSLog(@"YES") : NSLog(@"NO"); 

Log đầu ra:

NO
YES
NO
YES

này là cực kỳ bực bội với tôi. Tôi biết điều này có lẽ là do sự khác biệt giữa số bit trong một phao so với một đôi. Dường như với tôi nó cắt ngắn đôi xuống một phao để làm so sánh. Nhưng nếu tôi không biết làm thế nào số được tạo ra, làm thế nào để tôi có được kết quả chính xác? Có cách nào khác để so sánh NSNumber không?

+3

gì về nếu bạn sử dụng '[number1 isEqualToNumber: number2] ', đó là cách ưa thích, ít nhất là nếu bạn chỉ cố gắng xác định sự bình đẳng của các giá trị? – twilson

+1

Xin lỗi twilson, vẫn trả về NO. Các số khác nhau. – picciano

Trả lời

7

tôi đã cố gắng sử dụng isEqualToNumber: và nó trở NO. Lý do chúng không giống nhau bởi vì 1.004 không thể được biểu diễn chính xác theo dạng nhị phân. Số xấp xỉ double có nhiều chữ số hơn sau dấu thập phân so với xấp xỉ float để hai số khác nhau. Thông thường, khi so sánh số dấu chấm động, bạn kiểm tra để xem nếu họ đều bình đẳng để trong vòng một giá trị khoan dung fabs(a - b) < tolerance:

NSNumber* number1 = [NSNumber numberWithFloat:1.004]; 
NSNumber* number2 = [NSNumber numberWithDouble:1.004]; 

NSLog(@"number 1: %.12f", [number1 doubleValue]); 
NSLog(@"number 2: %.12f", [number2 doubleValue]); 

([number1 isEqualToNumber:number2]) ? NSLog(@"YES") : NSLog(@"NO"); 
fabs([number1 floatValue] - [number2 doubleValue]) < 1.0e-7 ? NSLog(@"YES") : NSLog(@"NO"); 

kết quả:

2012-02-09 15:08:34.272 so9219935[3313:903] number 1: 1.003999948502 
2012-02-09 15:08:34.274 so9219935[3313:903] number 2: 1.004000000000 
2012-02-09 15:08:34.275 so9219935[3313:903] NO 
2012-02-09 15:08:34.275 so9219935[3313:903] YES 
+0

Giải pháp rất tốt! Nó có vẻ điên rồ với tôi rằng Apple không xử lý điều này với so sánh: phương pháp ... –

+5

Apple (hoặc, chính xác hơn, các nhà văn biên dịch) không thể đưa ra giả định về sự khoan dung của lập trình viên đối với bình đẳng. Tất cả những gì họ có thể làm là chính xác những gì các lập trình viên bảo họ làm. Trong trường hợp này, bạn đã so sánh hai giá trị không bằng nhau.Số dấu chấm động không phải là một chủ đề tầm thường. Nếu bạn có thời gian, hãy xem [Mỗi nhà khoa học máy tính nên biết gì về số học dấu chấm động] (http://www-users.math.umd.edu/~jkolesar/mait613/floating_point_math.pdf). – SSteve

+0

Cảm ơn bạn đã tham khảo! Tôi đã tìm kiếm một đề nghị đọc về điều này. Tôi đã biết về vấn đề này trong một thời gian, chỉ cần không làm bất cứ điều gì về nó. :) –

2

Phương pháp so sánh tuân theo quy tắc C chuẩn cho chuyển đổi loại. Ví dụ, nếu bạn so sánh một đối tượng NSNumber có một giá trị số nguyên với một đối tượng NSNumber có một giá trị dấu chấm động, giá trị số nguyên được chuyển đổi thành một giá trị dấu phẩy động để so sánh.

Ngoài ra, khởi tạo một NSNumber với một phao, sau đó chuyển đổi nó thành một đôi mất một số độ chính xác.

NSNumber* number1 = [NSNumber numberWithFloat:1.004]; 
NSNumber* number2 = [NSNumber numberWithDouble:1.004]; 
NSLog(@"number1 double: %1.16f", [number1 doubleValue]); 
NSLog(@"number2 double: %1.16f", [number2 doubleValue]); 
NSLog(@"number1 objCType %s", [number1 objCType]); 
NSLog(@"number2 objCType %s", [number2 objCType]); 

2012-02-09 15:59:49.487 testNSNumber[89283:f803] number1 double: 1.0039999485015869 
2012-02-09 15:59:49.488 testNSNumber[89283:f803] number2 double: 1.0040000000000000 
2012-02-09 16:21:01.655 testNSNumber[4351:f803] number1 objCType f 
2012-02-09 16:21:01.656 testNSNumber[4351:f803] number2 objCType d 

Nếu bạn biết bạn có thể có một kết hợp của phao và đôi, một giải pháp là để so sánh floatValues ​​NSNumber như bạn đã làm trong dòng cuối cùng của đoạn mã của bạn trong câu hỏi của bạn.

Ngoài ra, bạn có thể lấy loại dữ liệu trong NSNumber bằng phương pháp objCType.

+0

Tôi thực sự thích objType đó! Cảm ơn bạn! –

2

hãy thử các isEqualToNumber: phương pháp để kiểm tra tình trạng của bạn

([number1 isEqualToNumber:number2]) ? NSLog(@"YES") : NSLog(@"NO"); 

this stackoverflow question cũng đưa ra một câu trả lời chi tiết

+0

Điều này sẽ không hoạt động như mong đợi và sẽ ghi "KHÔNG". NSNumbers khởi tạo với float và double sẽ là các giá trị khác nhau. Xem câu trả lời của tôi ở trên. Câu hỏi SO bạn tham chiếu đang sử dụng tất cả các phao. – picciano