Check if NSDecimalNumber is whole number
Asked Answered
S

7

4

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

Thanks!

Sekofski answered 6/9, 2012 at 11:9 Comment(3)
I am not sure. What about if ([myDecNumber isEqualToNumber:[myDecNumber integerValue]])?Diverticulum
Just cast your decimal value to int and check if its the sameDevilment
Maybe something like this: if ([myDecimalNumber decimalValue] / 1.0) > 0) {}?Dogeatdog
D
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
Dentoid answered 6/9, 2012 at 17:7 Comment(0)
K
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!");
}
Kronick answered 6/9, 2012 at 11:30 Comment(3)
I submitted an edit of the answer and changed one 'double' to 'int'. However, I think that the origial version would work fine as well. Sorry to bother you.Diverticulum
Any method that use double cannot be used with NSDecimalNumber. What if the number has 30 digits?Siesta
This is simpliest solution!Olivia
S
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.

Siesta answered 6/9, 2012 at 13:53 Comment(3)
I haven't had the chance to test it out yet, but this seems to be the solution I'm looking for. Thank you.Sekofski
@Sekofski Also check out Jody Hagins' answer.Siesta
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.Sekofski
P
0

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

Pitt answered 6/9, 2012 at 11:51 Comment(0)
E
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];
Escarole answered 6/9, 2012 at 11:52 Comment(4)
You lose precision. double cannot cover all the values from NSDecimalNumber.Siesta
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.Sekofski
@Siesta Yes because double is base-2 while NSDecimalNumber is base-10.Escarole
@Sekofski 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!Siesta
O
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;
}
Odelsting answered 10/8, 2014 at 3:13 Comment(0)
I
-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");
Interceptor answered 6/9, 2012 at 11:24 Comment(4)
Not really good for localization. And what if the number is "2.0" ?Siesta
NSDecimalNumber automatically converts 20.0 to 20. Please check it your selfInterceptor
Can you check the above code by assigning 2.0 to decNumb. Somehow NSDecimalNumber seems to standardize 2.0 to 2.Interceptor
Yes, it does that but it's undocumented behavior.Siesta

© 2022 - 2024 — McMap. All rights reserved.