0

I've seen a similar topic about this a while back, but that seemed to be because the equation used NSNumber somewhere. I've checked all my code and all I can see is that I'm using NSDecimalNumbers for my equations.

I got a JSON webservice that returns some pricing numbers.

Just after parsing them in object properties I want to run the following equation with them:

NetPrice * ( 1 + (RawPercentage / 100)) + FixedPrice = processedNetPrice

Update: I changed the code to this:

    NSDecimalNumber *one = [NSDecimalNumber one];

    if (!self.netPrice || [self.netPrice isKindOfClass:[NSNull class]]) 
    { self.netPrice = [NSDecimalNumber zero]; }

    NSDecimalNumber *nettoPrijs = self.netPrice;
    NSLog(@"self.netPrice = %@",self.netPrice);
    //Returns: self.netPrice = 89.25

    NSLog(@"nettoPrijs = %@",nettoPrijs);
    //Returns: nettoPrijs = 89.25

    if (!self.userData.BandFixed || [self.userData.BandFixed isKindOfClass:[NSNull class]]) 
    { self.userData.BandFixed = [NSDecimalNumber zero]; }

    NSDecimalNumber *fixedPrice = self.userData.BandFixed;

    NSLog(@"self.userData.BandFixed = %@",self.userData.BandFixed);
    //Returns: self.userData.BandFixed = 0

    NSLog(@"fixedPrice = %@",fixedPrice);
    //Returns: fixedPrice = 0

    if (!self.userData.BandPercentage || [self.userData.BandPercentage isKindOfClass:[NSNull class]]) 
    { self.userData.BandPercentage = [NSDecimalNumber zero]; }

    NSDecimalNumber *rawPercentage = self.userData.BandPercentage;

    NSLog(@"self.userData.BandPercentage = %@",self.userData.BandPercentage);
    //Returns: self.userData.BandPercentage = 0

    NSLog(@"rawPercentage = %@",rawPercentage);
    //Returns: rawPercentage = 0

    NSDecimalNumber *percentage = [rawPercentage decimalNumberByMultiplyingByPowerOf10:-2];
    NSLog(@"percentage = %@",percentage);
    //Returns: percentage = 0

    NSDecimalNumber *onePercent = [one decimalNumberByAdding:percentage];
    NSLog(@"onePercent = %@",onePercent);
    //Returns: onePercent = 1

    NSDecimalNumber *onePercentTimesNetPrice = [onePercent decimalNumberByMultiplyingBy:nettoPrijs];
    NSLog(@"onePercentTimesNetPrice = %@",onePercentTimesNetPrice);
    //Returns: onePercentTimesNetPrice =        
    -0.000000000000000000000000000000000000000000000000000000000000000000000
    00000000000000000000000000359498933794611654993903616

    NSDecimalNumber *addingFixed = [onePercentTimesNetPrice decimalNumberByAdding:fixedPrice];
    NSLog(@"addingFixed = %@",addingFixed);
    //Returns: addingFixed =  
    -0.000000000000000000000000000000000000000000000000000000000000000000000
    00000000000000000000000000359498933794611654993903616

If I change:

NSDecimalNumber *onePercentTimesNetPrice = [onePercent decimalNumberByMultiplyingBy:nettoPrijs];

to:

NSDecimalNumber *onePercentTimesNetPrice = [nettoPrijs decimalNumberByMultiplyingBy:onePercent];

it crashes:

-[__NSCFNumber decimalNumberByMultiplyingBy:]: unrecognized selector sent to instance 0x84ad160
Community
  • 1
  • 1
blaa
  • 438
  • 5
  • 19
  • Try to focus your question. For me it's to long to get my head around during the few minutes I have during work. – dasdom Dec 10 '12 at 12:52
  • Edited it for you. Hopefully this is more focused :) – blaa Dec 10 '12 at 13:01
  • What exactly is your question? I don't see what you mean by "this". – jimpic Dec 10 '12 at 13:06
  • How come: 89.25 * ( 1+ ((null)/100) )+ (null) = -0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000133763189343321587712 ? – blaa Dec 10 '12 at 13:08
  • Why do you need to use `NSDecimalNumber` in the first place? They are pain in the rear to use. – trojanfoe Dec 10 '12 at 13:17
  • Tell me about it! Got any better alternative? I read at CIMGF that you should always use NSDecimalNumbers for money-related stuffs. I'm quite new to Obj-C, so I could be wrong though :). – blaa Dec 10 '12 at 15:06
  • What's wrong with `float` or `double`? They are simple, fast and work as expected. – trojanfoe Dec 10 '12 at 15:09
  • Well, because of [this](http://www.cimgf.com/2008/04/23/cocoa-tutorial-dont-be-lazy-with-nsdecimalnumber-like-me/) :"If you are dealing with currency at all, then you should be using NSDecimalNumber." and [this](http://floating-point-gui.de/basic/) :"If you really need your results to add up exactly, especially when you work with money: use a special decimal datatype." – blaa Dec 10 '12 at 15:12

2 Answers2

1

As your NSLog() output shows, self.userData.RawPercentage and self.userData.FixedPrice are nil, i.e. are not allocated + initialized as NSDecimalNumber objects.

nil cannot be used to represent the decimal number zero!

In fact, when I try your code,

NSDecimalNumber *custPrice1 = [oneWithNet decimalNumberByAdding:priceFixed];

crashes because priceFixed is nil.

So you should check the code where these variables are initialized and make sure that they point to valid NSDecimalNumber objects.


UPDATE: The error message

-[__NSCFNumber decimalNumberByMultiplyingBy:]: unrecognized selector sent to instance 0x84ad160

shows that nettoPrijs is a NSNumber object and not a NSDecimalNumber. The following simplified code shows what happens if you try to multiply a NSDecimalNumber with a NSNumber:

NSDecimalNumber *one = [NSDecimalNumber one];
id price = [NSNumber numberWithFloat:89.25];
NSDecimalNumber *product = [one decimalNumberByMultiplyingBy:price];
NSLog(@"product = %@", product);
// Output:
// product = -0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221166721562906606351581184

(I have no idea why this doesn't crash or produce some error message.) It works correctly if you multiply with a NSDecimalNumber:

price = [NSDecimalNumber decimalNumberWithString:@"89.25"];
product = [one decimalNumberByMultiplyingBy:price];
NSLog(@"product = %@", product);
// Output:
// product = 89.25

So I assume that self.netPrice is a NSNumber object which has to be converted to a NSDecimalNumber. The same may apply to the other number objects.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • I use `if (!property || property == NULL || [property isKindOfClass:[NSNull class]]) { property = [NSDecimalNumber zero]; }` blocks before all of those to check if it returns nil, and then make it `[NSDecimalNumber zero]`. Hope that helps. – blaa Dec 10 '12 at 13:22
  • 1
    @VincentVeldkamp `!property` and `property == NULL` are the same test. – trojanfoe Dec 10 '12 at 13:25
  • 1
    In that case I cannot reproduce the problem, my output is "custPrice: 89.25". – Martin R Dec 10 '12 at 13:26
  • I'll check my code again and try and check where it goes wrong. Will fix the double test. Thanks so far! – blaa Dec 10 '12 at 13:28
0

I fixed it using:

- (void) doMath
{
    NSDecimalNumber *one = [NSDecimalNumber one];
    NSLog(@"Band: %@ one = %@",self,one);
    if (!self.netPrice || [self.netPrice isKindOfClass:[NSNull class]]) { self.netPrice = [NSDecimalNumber zero]; }
    NSDecimalNumber *nettoPrijs = self.netPrice;
    NSLog(@"self.netPrice = %@",self.netPrice);
    NSLog(@"nettoPrijs = %@",nettoPrijs);
    if (!self.userData.BandFixed || [self.userData.BandFixed isKindOfClass:[NSNull class]]) { self.userData.BandFixed = [NSDecimalNumber zero]; }
    NSDecimalNumber *fixedPrice = self.userData.BandFixed;
    NSLog(@"self.userData.BandFixed = %@",self.userData.BandFixed);
    NSLog(@"fixedPrice = %@",fixedPrice);
    if (!self.userData.BandPercentage || [self.userData.BandPercentage isKindOfClass:[NSNull class]]) { self.userData.BandPercentage = [NSDecimalNumber zero]; }
    NSDecimalNumber *rawPercentage = self.userData.BandPercentage;
    NSLog(@"self.userData.BandPercentage = %@",self.userData.BandPercentage);
    NSLog(@"RawPercentage = %@",rawPercentage);
    NSDecimalNumber *percentage = [rawPercentage decimalNumberByMultiplyingByPowerOf10:-2];
    NSLog(@"percentage = %@",percentage);
    NSDecimalNumber *onePercent = [one decimalNumberByAdding:percentage];
    NSLog(@"onePercent = %@",onePercent);

NSDecimalNumber gertje = [NSDecimalNumber decimalNumberWithDecimal:nettoPrijs.decimalValue]; * NSDecimalNumber *onePercentTimesNetPrice = [gertje decimalNumberByMultiplyingBy:onePercent];

    NSLog(@"onePercentTimesNetPrice = %@",onePercentTimesNetPrice);
    NSDecimalNumber *addingFixed = [onePercentTimesNetPrice decimalNumberByAdding:fixedPrice];
    NSLog(@"addingFixed = %@",addingFixed);
}

Thanks for all your help!

blaa
  • 438
  • 5
  • 19