比较 NSDecimalNumber 的不同方法

发布于 2024-12-29 10:01:32 字数 651 浏览 3 评论 0原文

例如,对于原语,我将这样做,

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,因为我在这里处理货币。或者,如果我确实将它们转换为上面提到的那些,有人可以验证/解释精度吗?

For example, with primitive, I'll do this

if ( (x >= 6000) && (x <= 20000) )
    // do something here 

and with NSDecimalNumber, this is what I have

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. Or if I do convert them to those mentioned above, can someone verify / explain about the precision?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

如果没结果 2025-01-05 10:01:32

我的理解是,您只能使用 compare: 方法比较 NSDecimalNumberNSNumber 对象。超级令人沮丧,但我相信这是因为 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 文档 建议您在进行以 10 为基数的算术运算时使用它。

My understanding is that you can only compare NSDecimalNumber and NSNumber objects using the compare: method. Super frustrating, but I believe it stems from Objective-C not supporting operator overloading.

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. 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.

暖心男生 2025-01-05 10:01:32

NSDecimalNumber+Comparison 类别代码

@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

NSDecimalNumber+Comparison Category Code

@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

Unit Tests for good measure

@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
谈场末日恋爱 2025-01-05 10:01:32

compare 方法返回 NSOrderedDescendingNSOrderedAscendingNSOrderedSame

相反,您可以轻松地编写

if ( 
    [x compare:[NSNumber numberWithInt:6000]] != NSOrderedAscending && 
    [x compare:[NSNumber numberWithInt:20000]] != NSOrderedDescending
)
{
    // do something here
}

哪个可读性更好。

compare method returns NSOrderedDescending, NSOrderedAscending or 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.

你的他你的她 2025-01-05 10:01:32
if(([x doubleValue]>=6000.0f) && ([x doubleValue] <=20000.0f))

我认为这也会相当精确。

if(([x doubleValue]>=6000.0f) && ([x doubleValue] <=20000.0f))

I think this will be rather preciese too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文