views:

588

answers:

2

I am confused by NSDecimalNumber and its "behaviors". I have an NSDecimalNumber that represents a dollar value, say $37.50. I'd like to find out how many times say 5.0 goes into that number and then know what's left over. I can get the straight division and get 7.50 but I want 7 mod 2.50. I could convert to an integer but need to save the "cents" so wondering if there's some tricks in the framework?

+1  A: 

You could theoretically do some tricks with the NSDecimalNumber methods decimalNumberByDividingBy:, decimalNumberByMultiplyingBy:, and decimalValue. Divide the numbers, grab the decimal number structure, figure out the remainder from the structure, then create a new decimal number with that remainder and multiply that remainder by the original number.

The easier way to do it, however, would probably be to figure out the maximum precision you want (call it N places after the decimal point), multiply the number by 10eN, then just grab the integer value and do your division and mod on that. You run the risk of losing data, especially with very large numbers, however, so check the biggest number you want and figure out what data type - if any - will work for you. NSNumber does support unsignedLongLongValue.

Tim
+2  A: 
  1. Divide the dividend by the divisor, rounding down. This gets you the quotient.
  2. Multiply the divisor by the quotient.
  3. Subtract that from the dividend. This gets you the remainder.

(37.50 // 5) == 7; 7 * 5 == 35; 37.50 - 35 = 2.50.

(Note: // is Python's operator for integral division. I've borrowed it here. Obviously, you should not actually attempt to use // for division in Objective-C code.)

Peter Hosey
To round down, use floor() from math.h — it takes a double and returns a double.
Quinn Taylor
If you're using decimal numbers, try to stay within that type as much as possible. Namely, to round use decimalNumberByRoundingAccordingToBehavior:.
Tim
Better yet, use `decimalNumberByDividingBy:withBehavior:` to do the division. Then you don't need to round separately.
Peter Hosey