I need to get the absolute value of an NSDecimalNumber without loss of precision. I can\'t seem to find a way to do this without converting to decimal or float (with a loss
You can use the built-in functions of the NSDecimalNumber class to compare the number to zero, then multiply by -1 as appropriate. For example:
- (NSDecimalNumber *)abs:(NSDecimalNumber *)num {
if ([num compare:[NSDecimalNumber zero]] == NSOrderedAscending) {
// Number is negative. Multiply by -1
NSDecimalNumber * negativeOne = [NSDecimalNumber decimalNumberWithMantissa:1
exponent:0
isNegative:YES];
return [num decimalNumberByMultiplyingBy:negativeOne];
} else {
return num;
}
}
Since this method works solely with NSDecimalNumbers, there's no loss of precision.
There is a minor error in the answer: negativeOne should be a pointer. Here is a revised answer:
- (NSDecimalNumber *)abs:(NSDecimalNumber *)num {
if [myNumber compare:[NSDecimalNumber zero]] == NSOrderedAscending) {
// Number is negative. Multiply by -1
NSDecimalNumber *negativeOne = [NSDecimalNumber decimalNumberWithMantissa:1
exponent:0
isNegative:YES];
return [num decimalNumberByMultiplyingBy:negativeOne];
} else {
return num;
}
}
And here is a version suitable to be used as a category on NSDecimalNumber:
- (NSDecimalNumber *)abs {
if ([self compare:[NSDecimalNumber zero]] == NSOrderedAscending) {
// Number is negative. Multiply by -1
NSDecimalNumber *negativeOne = [NSDecimalNumber decimalNumberWithMantissa:1
exponent:0
isNegative:YES];
return [self decimalNumberByMultiplyingBy:negativeOne];
} else {
return self;
}
}
If you do not want to multiply it, zero subtracting the value will do the trick.
- (NSDecimalNumber *)abs:(NSDecimalNumber *)num {
if ([num compare:[NSDecimalNumber zero]] == NSOrderedAscending) {
// negative value
return [[NSDecimalNumber zero] decimalNumberBySubtracting:num];
} else {
return num;
}
}
Swift 4.0 variant:
extension NSDecimalNumber {
func absoluteValue() -> NSDecimalNumber {
if self.compare(NSDecimalNumber.zero) == .orderedAscending {
let negativeValue = NSDecimalNumber(mantissa: 1, exponent: 0, isNegative: true)
return self.multiplying(by: negativeValue)
} else {
return self
}
}
}
usage
let sum = NSDecimalNumber(value: -123.33)
sum.absoluteValue()