Различные способы сравнения NSDecimalNumber
Например, с примитивным, я сделаю это
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, так как я обрабатываю валюту здесь. Или, если я преобразовываю их в упомянутые выше, может ли кто-нибудь проверить/объяснить точность?
Ответы
Ответ 1
Я понимаю, что вы можете сравнивать объекты 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 является оптимальным в валютных сценариях. Этот ответ дает неплохую оценку того, почему плавающие (и парные) недостаточно точны при работе с валютой. Кроме того, Документация Apple для NSDecimalNumber рекомендует его использовать, когда вы делаете арифметику base-10.
Ответ 2
NSDecimalNumber + Код категории сравнения
@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
Ответ 3
if(([x doubleValue]>=6000.0f) && ([x doubleValue] <=20000.0f))
Я думаю, что это тоже будет довольно сложным.
Ответ 4
compare
возвращает NSOrderedDescending
, NSOrderedAscending
или NSOrderedSame
Вместо этого вы можете легко написать
if (
[x compare:[NSNumber numberWithInt:6000]] != NSOrderedAscending &&
[x compare:[NSNumber numberWithInt:20000]] != NSOrderedDescending
)
{
// do something here
}
Это немного лучше читаемо.