[英]Different ways of comparing NSDecimalNumber
For example, with primitive, I'll do this 例如,对于原始,我会这样做
if ( (x >= 6000) && (x <= 20000) )
// do something here
and with NSDecimalNumber, this is what I have 并且使用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
}
Is there any other ways (easier and more elegant) to this comparison? 这种比较还有其他方法(更简单,更优雅)吗? If I convert the value to primitive, what primitive do I use?
如果我将值转换为原始,我使用什么原语? I don't want to use CGFloat, float or double, as I'm handling with currency here.
我不想使用CGFloat,float或double,因为我在这里处理货币。 Or if I do convert them to those mentioned above, can someone verify / explain about the precision?
或者如果我将它们转换为上面提到的那些,有人可以验证/解释精度吗?
My understanding is that you can only compare NSDecimalNumber
and NSNumber
objects using the compare:
method. 我的理解是你只能使用
compare:
方法比较NSDecimalNumber
和NSNumber
对象。 Super frustrating, but I believe it stems from Objective-C not supporting operator overloading. 超级令人沮丧,但我认为它源于Objective-C不支持运算符重载。
If it's becoming really difficult to read, you could always add a category with some helper methods to try and make it a little more readable, something like this perhaps? 如果它变得非常难以阅读,你总是可以添加一个带有一些辅助方法的类别来尝试使它更具可读性,这可能是这样的吗?
// 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];
}
Then things become a little more human-readable: 然后事情变得更具人性化:
if([x isGreaterThanOrEqualToInt:6000] && [x isLessThanOrEqualToInt:20000]){
//...
}
Edit I just noticed that you'd also asked about why using NSDecimalNumber is optimal in currency scenarios. 编辑我刚刚注意到你也问过为什么在货币场景中使用NSDecimalNumber是最优的。 This answer gives a pretty good run down on why floats (and doubles) are not precise enough when working with currency.
这个答案很好地说明了为什么浮点数(和双打数)在使用货币时不够精确。 Furthermore, Apple's documentation for NSDecimalNumber recommends its use whenever you're doing base-10 arithmetic.
此外, Apple的NSDecimalNumber文档建议在您进行base-10算术时使用它。
@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
compare
method returns NSOrderedDescending
, NSOrderedAscending
or NSOrderedSame
compare
方法返回NSOrderedDescending
, NSOrderedAscending
或NSOrderedSame
Instead you can then easily write 相反,你可以轻松写
if (
[x compare:[NSNumber numberWithInt:6000]] != NSOrderedAscending &&
[x compare:[NSNumber numberWithInt:20000]] != NSOrderedDescending
)
{
// do something here
}
Which is slighty better readable. 哪个更易读。
if(([x doubleValue]>=6000.0f) && ([x doubleValue] <=20000.0f))
我认为这也是相当精确的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.