例如,对于原语,我会这样做
if ( (x >= 6000) && (x <= 20000) )
// do something here
并且使用NSDecimalNumber,这就是我所拥有的
if ( (([x compare:[NSNumber numberWithInt:6000]] == NSOrderedSame) ||
([x compare:[NSNumber numberWithInt:6000]] == NSOrderedDescending))
&& (([x compare:[NSNumber numberWithInt:20000]] == NSOrderedSame) ||
([x compare:[NSNumber numberWithInt:6000]] == NSOrderedAscending)) )
{
// do something here
}
这种比较还有其他方法(更简单,更优雅)吗?如果我将值转换为原始,我使用什么原语?我不想使用CGFloat,float或double,因为我在这里处理货币。或者,如果我将它们转换为上面提到的那些,有人可以验证/解释精度吗?
答案 0 :(得分:23)
我的理解是,您只能使用NSDecimalNumber
方法比较NSNumber
和compare:
个对象。超级令人沮丧,但我认为它源于Objective-C不支持运算符重载。
如果它变得非常难以阅读,你总是可以添加一个带有一些辅助方法的类别来尝试使它更具可读性,或许这样吗?
// NSNumber+PrimativeComparison.m
- (NSComparisonResult) compareWithInt:(int)i{
return [self compare:[NSNumber numberWithInt:i]]
}
- (BOOL) isEqualToInt:(int)i{
return [self compareWithInt:i] == NSOrderedSame;
}
- (BOOL) isGreaterThanInt:(int)i{
return [self compareWithInt:i] == NSOrderedDescending;
}
- (BOOL) isGreaterThanOrEqualToInt:(int)i{
return [self isGreaterThanInt:i] || [self isEqualToInt:i];
}
- (BOOL) isLessThanInt:(int)i{
return [self compareWithInt:i] == NSOrderedAscending;
}
- (BOOL) isLessThanOrEqualToInt:(int)i{
return [self isLessThanInt:i] || [self isEqualToInt:i];
}
然后事情变得更具人性化了:
if([x isGreaterThanOrEqualToInt:6000] && [x isLessThanOrEqualToInt:20000]){
//...
}
编辑我刚刚注意到您还询问为什么使用NSDecimalNumber在货币方案中是最佳的。 This answer给出了一个很好的说明为什么浮点数(和双打)在使用货币时不够精确。此外,Apple's documentation for NSDecimalNumber建议在使用base-10算法时使用它。
答案 1 :(得分:5)
@interface NSDecimalNumber (Comparison)
- (BOOL)isLessThan:(NSDecimalNumber *)decimalNumber;
- (BOOL)isLessThanOrEqualTo:(NSDecimalNumber *)decimalNumber;
- (BOOL)isGreaterThan:(NSDecimalNumber *)decimalNumber;
- (BOOL)isGreaterThanOrEqualTo:(NSDecimalNumber *)decimalNumber;
- (BOOL)isEqualToDecimalNumber:(NSDecimalNumber *)decimalNumber;
@end
@implementation NSDecimalNumber (Comparison)
- (BOOL)isLessThan:(NSDecimalNumber *)decimalNumber
{
return [self compare:decimalNumber] == NSOrderedAscending;
}
- (BOOL)isLessThanOrEqualTo:(NSDecimalNumber *)decimalNumber
{
return [self compare:decimalNumber] != NSOrderedDescending;
}
- (BOOL)isGreaterThan:(NSDecimalNumber *)decimalNumber
{
return [self compare:decimalNumber] == NSOrderedDescending;
}
- (BOOL)isGreaterThanOrEqualTo:(NSDecimalNumber *)decimalNumber
{
return [self compare:decimalNumber] != NSOrderedAscending;
}
- (BOOL)isEqualToDecimalNumber:(NSDecimalNumber *)decimalNumber
{
return [self compare:decimalNumber] == NSOrderedSame;
}
@end
@interface NSDecimalNumber_Comparison_Tests : XCTestCase
@end
@implementation NSDecimalNumber_Comparison_Tests
#pragma mark - isLessThan: tests
- (void)test_isLessThan_whenGreaterThan_returnsNO
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6779"];
BOOL result = [decimalNumberA isLessThan:decimalNumberB];
XCTAssertFalse(result);
}
- (void)test_isLessThan_whenLessThan_returnsYES
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6781"];
BOOL result = [decimalNumberA isLessThan:decimalNumberB];
XCTAssertTrue(result);
}
- (void)test_isLessThan_whenEqualTo_returnsNO
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
BOOL result = [decimalNumberA isGreaterThan:decimalNumberB];
XCTAssertFalse(result);
}
#pragma mark - isLessThanOrEqualTo: tests
- (void)test_isLessThanOrEqualTo_whenGreaterThan_returnsNO
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6779"];
BOOL result = [decimalNumberA isLessThanOrEqualTo:decimalNumberB];
XCTAssertFalse(result);
}
- (void)test_isLessThanOrEqualTo_whenLessThan_returnsYES
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6781"];
BOOL result = [decimalNumberA isLessThanOrEqualTo:decimalNumberB];
XCTAssertTrue(result);
}
- (void)test_isLessThanOrEqualTo_whenEqualTo_returnsYES
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
BOOL result = [decimalNumberA isLessThanOrEqualTo:decimalNumberB];
XCTAssertTrue(result);
}
#pragma mark - isGreaterThan: tests
- (void)test_isGreaterThan_whenGreaterThan_returnsYES
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6779"];
BOOL result = [decimalNumberA isGreaterThan:decimalNumberB];
XCTAssertTrue(result);
}
- (void)test_isGreaterThan_whenLessThan_returnsNO
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6781"];
BOOL result = [decimalNumberA isGreaterThan:decimalNumberB];
XCTAssertFalse(result);
}
- (void)test_isGreaterThan_whenEqualTo_returnsNO
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
BOOL result = [decimalNumberA isGreaterThan:decimalNumberB];
XCTAssertFalse(result);
}
#pragma mark - isGreaterThanOrEqualTo: tests
- (void)test_isGreaterThanOrEqualTo_whenGreaterThan_returnsYES
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6779"];
BOOL result = [decimalNumberA isGreaterThanOrEqualTo:decimalNumberB];
XCTAssertTrue(result);
}
- (void)test_isGreaterThanOrEqualTo_whenLessThan_returnsNO
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6781"];
BOOL result = [decimalNumberA isGreaterThanOrEqualTo:decimalNumberB];
XCTAssertFalse(result);
}
- (void)test_isGreaterThanOrEqualTo_whenEqualTo_returnsYES
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
BOOL result = [decimalNumberA isGreaterThanOrEqualTo:decimalNumberB];
XCTAssertTrue(result);
}
#pragma mark - isEqualToDecimalNumber: tests
- (void)test_isEqualToDecimalNumber_whenGreaterThan_returnsNO
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6779"];
BOOL result = [decimalNumberA isEqualToDecimalNumber:decimalNumberB];
XCTAssertFalse(result);
}
- (void)test_isEqualToDecimalNumber_whenLessThan_returnsNO
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6781"];
BOOL result = [decimalNumberA isEqualToDecimalNumber:decimalNumberB];
XCTAssertFalse(result);
}
- (void)test_isEqualToDecimalNumber_whenEqualTo_returnsYES
{
NSDecimalNumber *decimalNumberA = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
NSDecimalNumber *decimalNumberB = [NSDecimalNumber decimalNumberWithString:@"4.6780"];
BOOL result = [decimalNumberA isEqualToDecimalNumber:decimalNumberB];
XCTAssertTrue(result);
}
@end
答案 2 :(得分:3)
if(([x doubleValue]>=6000.0f) && ([x doubleValue] <=20000.0f))
我认为这也是相当精确的。
答案 3 :(得分:3)
compare
方法返回NSOrderedDescending
,NSOrderedAscending
或NSOrderedSame
相反,您可以轻松编写
if (
[x compare:[NSNumber numberWithInt:6000]] != NSOrderedAscending &&
[x compare:[NSNumber numberWithInt:20000]] != NSOrderedDescending
)
{
// do something here
}
哪个更易读。