4

What's the easiest way to check if an instance of NSDecimalNumber is a whole number?

Thanks!

Parag Bafna
  • 22,812
  • 8
  • 71
  • 144
James
  • 762
  • 8
  • 22

7 Answers7

10
@interface NSDecimalNumber (IsIntegerNumber)
@property (readonly) BOOL isIntegerNumber;
@end

@implementation NSDecimalNumber (IsIntegerNumber)
-(BOOL)isIntegerNumber {
    NSDecimalValue value = [self decimalValue];
    if (NSDecimalIsNotANumber(&value)) return NO;
    NSDecimal rounded;
    NSDecimalRound(&rounded, &value, 0, NSRoundPlain);
    return NSDecimalCompare(&rounded, &value) == NSOrderedSame;
}
@end
Jody Hagins
  • 27,943
  • 6
  • 58
  • 87
3

Subtract the whole number from the decimal number. If the difference is zero then the decimal number is a whole number.

// testVal is NSDecimalNumber
NSString *test = [testVal stringValue];
int intVal = [test intValue];
double doubleVal = [test doubleValue];
if(doubleVal-intVal == 0){
    NSLog(@"Whole number!");
}

Or, get the whole number and compare to the original value:

if(intVal == doubleVal){
    NSLog(@"Whole number!");
}
Hermann Klecker
  • 14,039
  • 5
  • 48
  • 71
yoninja
  • 1,952
  • 2
  • 31
  • 39
3

This should work.

Beware of using methods that convert NSDecimalNumber into double.

NSDecimalNumber* input = [...];

NSDecimal roundedDecimal;
NSDecimalRound(&roundedDecimal, [input decimalValue], 0, NSRoundPlain);

NSDecimalNumber* roundedNumber = [NSDecimalNumber decimalNumberWithDecimal:roundedDecimal];

BOOL inputIsWholeNumber = [input isEqualToNumber:roundedNumber];

You should also check for NaN values.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • I haven't had the chance to test it out yet, but this seems to be the solution I'm looking for. Thank you. – James Sep 07 '12 at 10:33
  • @James Also check out Jody Hagins' answer. – Sulthan Sep 07 '12 at 10:37
  • He/she submitted it right after accepted yours. I upvoted both, but I think changing the accepted answer to his/hers may be more helpful to others looking for a quick answer. Hope you don't mind. – James Sep 07 '12 at 10:40
0

Can you not use if ((number % 1) == 0)

Darren
  • 10,182
  • 20
  • 95
  • 162
0
@implementation NSDecimalNumber (isWholeNumber)
-(BOOL)isWholeNumber
{
    double x = [self doubleValue]; //The approximate value of the receiver as a double.
    double y = floor (x);
    if(fabs(x - y) < DBL_EPSILON)
      return YES;
    return NO;
}
@end  
// [myDecNumber isWholeNumber];
Parag Bafna
  • 22,812
  • 8
  • 71
  • 144
  • You lose precision. `double` cannot cover all the values from `NSDecimalNumber`. – Sulthan Sep 06 '12 at 13:04
  • I was under the impression that a tiny bit of precision is lost when converting `NSDecimalNumber` to `double` or `float`. I could be mistaken about this, but I'm curious to know if the outcome of this approach would be affected if that were indeed the case. Thanks. – James Sep 06 '12 at 13:05
  • @Sulthan Yes because double is base-2 while NSDecimalNumber is base-10. – Parag Bafna Sep 06 '12 at 13:22
  • 1
    @James The loss caused by base-10 to base-2 conversion is significant but the important thing is that a `NSDecimalNumber` can hold up to 38 decimal digits while `double` ony about 16 decimal digits! – Sulthan Sep 06 '12 at 13:28
0

Not sure why, but for some reason I was unable to get Jody Hagins' or Sulthan's solutions to work so I went a slightly different way:

-(BOOL)isWholeNumber:(NSDecimalNumber *)number {
    NSDecimalNumber *input = number;

    NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
                                                                                             scale:0
                                                                                  raiseOnExactness:NO
                                                                                   raiseOnOverflow:NO
                                                                                  raiseOnUnderflow:NO
                                                                               raiseOnDivideByZero:NO];

    NSDecimalNumber *vOne = [NSDecimalNumber decimalNumberWithString:@"1"];

    NSDecimalNumber *result = [number decimalNumberByMultiplyingBy:vOne
                                                      withBehavior:handler];

    BOOL inputIsWholeNumber = [input isEqualToNumber:result];

    return inputIsWholeNumber;
}
staticnz
  • 491
  • 1
  • 5
  • 15
-3

Try this, you can skip first line, i just used it to create a NSDecimalNumber object

NSDecimalNumber  *decNumb=[NSDecimalNumber decimalNumberWithString:@"20.5"];//try with just 20
NSString* str=[NSString stringWithFormat:@"%@",decNumb];

if ([str rangeOfString:@"."].location==NSNotFound && [str rangeOfString:@"-"].location==NSNotFound) {
    NSLog(@"it is whole number");
} 
else
    NSLog(@"it is not whole number");
Neo
  • 2,807
  • 1
  • 16
  • 18