0

I am making a iphone calculator app and I ran into this issue which I cannot seem to find a solution for.

When user enters numbers I convert them into double and then I convert that double result into a string. I am using %g to get whole numbers. The problem I have is for large numbers it shows a "E" exponent. This is what I have tried so far

    NSLog(@"Num1: %g", 5000.0*8.0);
    NSLog(@"Num2: %g", 500000.0*85.0);
    NSLog(@"Num3: %f", 500000.0*85.0);
    NSLog(@"Num4: %.4f", 5000.0*8.0);
    NSLog(@"Num5: %.4f", 500000.0*85.0);
    NSLog(@"Num6: %g", 5000000.0/3.7);
    NSLog(@"Num7: %.4f", 5000000.0/3.7); 

This is what I get in terms of results

    2013-10-20 14:09:34.261 ECalc[9947:a0b] Num1: 40000
2013-10-20 14:09:34.262 ECalc[9947:a0b] Num2: 4.25e+07
2013-10-20 14:09:34.263 ECalc[9947:a0b] Num3: 42500000.000000
2013-10-20 14:09:34.264 ECalc[9947:a0b] Num4: 40000.0000
2013-10-20 14:09:34.264 ECalc[9947:a0b] Num5: 42500000.0000
2013-10-20 14:09:34.265 ECalc[9947:a0b] Num6: 1.35135e+06
2013-10-20 14:09:34.266 ECalc[9947:a0b] Num7: 1351351.3514

Just like a normal calculator I would like to show whole numbers when numbers are multiplied normally. i.e.

Num2 = 42500000
Num7 = 1351351.3514

So here's my question, is there a string format specifier that I can use that will fit both num2 and num7 results? Do I need to use a lot of logic to see if the numbers after dot are zero then truncate them otherwise keep them and use %.4f?

Sam B
  • 27,273
  • 15
  • 84
  • 121
  • 6
    Don't use doubles and %f, use NSDecimalNumber and NSNumberFormatter. You don't want those [floating point problems](http://stackoverflow.com/questions/421463/should-i-use-nsdecimalnumber-to-deal-with-money) in a calculator. – Matthias Bauch Oct 20 '13 at 18:20
  • I don't get it? How does that fit the results? – Sam B Oct 20 '13 at 18:25
  • just general advice. Using those two classes will fix your problems. And it will even fix the localization problem you will encounter in the future. – Matthias Bauch Oct 20 '13 at 18:27
  • Thanks for the pointer but I feel like I am going on a wild goose chase. I cannot seems to fit the results of both num2 and num7 using just NSDecimalNumber and NSNumberFormatter – Sam B Oct 20 '13 at 18:38
  • Num2 and Num7 should be fine using `NSDecimalNumber`. What issue are you seeing? @MatthiasBauch is correct. Using `double` in a calculator app is going to be a real hassle. You're going to be chasing rounding errors all the time. – Rob Napier Oct 20 '13 at 19:39

1 Answers1

1

So, here's a quick and dirty solution to what you need.

double num1 = 5000.0*8.0;
double num7 = 5000000.0/3.7;

int decimalPlaces = 4;

if ((int) num1 == num1)
    NSLog(@"Num1: %0.0f",num1);
else
    NSLog(@"Num1: %0.*f", decimalPlaces, num1);

if ((int) num7 == num7)
    NSLog(@"Num1: %0.0f",num7);
else
    NSLog(@"Num1: %0.*f", decimalPlaces, num7);

But then you seemed to be concerned with actually being able to split up an NSString as well. So, the first block of code is the direction I recommend. If you're choosing to keep things complicated and stay within NSString throughout your calculator, then you can create a class that will split up an NSString and return to you either the whole number or the number with all its decimals. What I'm giving here is more than you need, but since you're new to iOS, hopefully it'll help you learn, there's a lot more you can do with this too, if you so desire.

-(NSString *)noZeroes:(NSString *)number
{
    int i = 0, decimalPos = 0;

    //NSRange says {startHere, forThisManyCharacters}
    NSRange subRange = {i, 1};
    NSString *substr = [number substringWithRange:subRange];

    while (i<[number length] && !([substr isEqualToString:@"."]))
    {
        i++;
        NSRange subRange = {i, 1};
        substr = [number substringWithRange:subRange];
    }

    //No decimal point in this number
    if (i == [number length])
        return number; //so return the number as is

    decimalPos = i+1;
    NSRange decimalRange = {decimalPos, [number length] - decimalPos};
    NSString *decimals = [number substringWithRange:decimalRange];

    NSRange wholeNumRange = {0, decimalPos};
    NSString *wholeNums =[number substringWithRange:wholeNumRange];

    //Numbers you don't want, you can put anything within a CharacterSet like this
    NSCharacterSet *notZeroes = [NSCharacterSet characterSetWithCharactersInString:@"123456789"];
    NSRange range = [decimals rangeOfCharacterFromSet:notZeroes];
    if (range.location == NSNotFound) {
        // nothing but zeroes in the string
        return wholeNums;

    } else {
        // nonzeroes are present
        return number;
    }
}

You would call this with something like:

NSString *Num1 = @"22345.56"
NSString *truncatedNum1 = [self noZeroes:Num1];
NSLog(@"Num1: %@", truncatedNum1);
Meshach
  • 315
  • 1
  • 2
  • 16
  • Meshach, wouldn't it be easier if I could break up the string into two parts i.e. 42500000 and .0000 if the last .0000 are all zeros then ignore them. Any idea how can I break up a string like that? – Sam B Oct 20 '13 at 18:55
  • I tried different scenarios for addition, subtraction and multiplication, division and it doesn't work reliably. Sorry. – Sam B Oct 20 '13 at 19:23
  • Here, rounding can have some inconsistencies, but if you cast to int it should be a little more reliable. – Meshach Oct 20 '13 at 19:34
  • Thanks meshach, I ended up using string and %.4f float and then breaking the string into two parts to get what I needed. I will rate your answer up as you had been helping quite a bit. Though I ended up doing things a bit differently and simpler. I will post that answer later. Thank you. – Sam B Oct 20 '13 at 19:36
  • But what if someone does 1/70000 ? I'm confused how a split on a specific set of 4 decimals is going to be consistent enough for a calculator. – Meshach Oct 20 '13 at 19:47