CS193P - Adding floating point button to iOS calculator
Asked Answered
S

10

7

I recently started following the online course on iPhone development from Stanford University on iTunes U.

I'm trying to do the homework assignments now for the first couple of lectures. I followed through the walkthrough where I built a basic calculator, but now I'm trying the first assignment and I can't seem to work it out. It's a follows:

Your calculator already works with floating point numbers (e.g. if you press 3 / 4 = it will properly show the resulting value of 0.75), however, there is no way for the user to enter a floating point number. Remedy this. Allow only legal floating point numbers to be entered (e.g. “192.168.0.1” is not a legal floating point number).

First of all, I'm not sure whether a floating point counts as digitPressed or operationPressed. I even tried with a new method called floatingPointPressed but that didn't really work out. Could someone provide pointers on this?

When I saw it as digitPressed, I tried something like this:

    if (hasFloatingPoint) {
        NSRange range = [[display text] rangeOfString:@"."];
        if (range.location == NSNotFound) 
        {
            [display setText:[[display text] stringByAppendingFormat:digit]];
            hasFloatingPoint = YES;
        }
    }
    else {
        [display setText:[[display text] stringByAppendingFormat:digit]];
    }

But I'm missing the key concept here, I think.

I have also tried another solution which I have, sadly, undone already so I can't provide the code but what happend was this: I could press a number, say 5 and then a floating point and 3 so I would end up with 5.3. I then managed to 'disable' the floating point for the remainder of the input.. But I guess I was a little too strict on it: I couldn't, for example, put in 5.3.2 but after pressing an operation button (+, etc), it still wouldn't let me press the floating point button. I guess I should reset the bool I used for this?

I'm not looking for a completely written out solution here, but could someone be so kind to provide some basic advice on how to tackle this problem? Some kind of step-by-step overview of what I should do and think about, without actually providing a code solution.

Thanks in advance.

Scraggy answered 18/6, 2011 at 12:29 Comment(0)
I
2

Since you want a hint of where to look, have a look at attaching a NSNumberFormatter to the input fields.

This is the proper way of validating input, rather than manually checking each character the user enters yourself.

edit I've just read the assignment that you are trying to work through. I think my answer here, although still the right way to do it, not the best way to do what the assignment is trying to get you to do.

Since you are reading the digits one by one as they are added to the view and appending them to the number you are operating on you may be on the right track with your original answer:

  • Keep accepting numbers as they are added
  • Add a decimalEntered flag - initialise it to 'NO'
  • If a decimal is entered, check the flag, if it is no, accept it and set the flag to YES
  • If a decimal is entered and the flag is YES, don't accept it.
  • Whenever you press an operand, set this flag back to NO.

When you learn a bit more, you'll realise that another way to do this is to let the user type in the field. Hook up a formatter to the field to validate that the input is a valid number, but it will also be able to turn the string into a number for you. And when an operand is pressed, this number will be kept aside as one of the numbers upon which the operand will operate.

Incommodity answered 18/6, 2011 at 13:54 Comment(4)
Okies, thank you. I'll check it out. Might be a bit advanced since I'm just starting out but I'll definitely take a look! Thanks.Scraggy
you'll be using the formatters a lot. Learning about them now might be a little more work, but it is the correct way to do what you're trying to do. And, if you get some code written and it doesn't work - you know where to come?Incommodity
Thanks. I accepted this answer because it helped me to understand the problem better than the code I wrote by trial and error. I'll look into formatters when I get more used to the code, it's a bit confusing atm.Scraggy
Good luck. It does get easier, really. The trouble with the first examples is they are so contrived - just to get you used to writing the code.Incommodity
S
5

Okay. I solved this. Was fairly easy once I managed to wrap my head around it:

-(IBAction)digitPressed:(UIButton *)sender
{
    NSString *digit = [[sender titleLabel] text];
    NSRange range = [[display text] rangeOfString:@"."];
    if (userIsInTheMiddleOfTypingANumber) 
    {
        if ( ! ([digit isEqual:@"."] && (range.location != NSNotFound))) {
            [display setText:[[display text] stringByAppendingFormat:digit]];
        }
    }
    else 
    {
        if ([digit isEqual:@"."]) {
            [display setText: @"0."];
        }
        else {
            [display setText: digit];
        }

        userIsInTheMiddleOfTypingANumber = YES;

    }

}
Scraggy answered 18/6, 2011 at 13:50 Comment(0)
I
2

Since you want a hint of where to look, have a look at attaching a NSNumberFormatter to the input fields.

This is the proper way of validating input, rather than manually checking each character the user enters yourself.

edit I've just read the assignment that you are trying to work through. I think my answer here, although still the right way to do it, not the best way to do what the assignment is trying to get you to do.

Since you are reading the digits one by one as they are added to the view and appending them to the number you are operating on you may be on the right track with your original answer:

  • Keep accepting numbers as they are added
  • Add a decimalEntered flag - initialise it to 'NO'
  • If a decimal is entered, check the flag, if it is no, accept it and set the flag to YES
  • If a decimal is entered and the flag is YES, don't accept it.
  • Whenever you press an operand, set this flag back to NO.

When you learn a bit more, you'll realise that another way to do this is to let the user type in the field. Hook up a formatter to the field to validate that the input is a valid number, but it will also be able to turn the string into a number for you. And when an operand is pressed, this number will be kept aside as one of the numbers upon which the operand will operate.

Incommodity answered 18/6, 2011 at 13:54 Comment(4)
Okies, thank you. I'll check it out. Might be a bit advanced since I'm just starting out but I'll definitely take a look! Thanks.Scraggy
you'll be using the formatters a lot. Learning about them now might be a little more work, but it is the correct way to do what you're trying to do. And, if you get some code written and it doesn't work - you know where to come?Incommodity
Thanks. I accepted this answer because it helped me to understand the problem better than the code I wrote by trial and error. I'll look into formatters when I get more used to the code, it's a bit confusing atm.Scraggy
Good luck. It does get easier, really. The trouble with the first examples is they are so contrived - just to get you used to writing the code.Incommodity
P
2
-(IBAction)floatingPoint:(UIButton *)sender {

    NSString *digit = sender.currentTitle;

    NSRange range = [self.display.text rangeOfString:@"."];

    if(range.location == NSNotFound){

        self.display.text = [self.display.text stringByAppendingString:digit];

       self.userIsInTheMiddleOfEnteringANumber = YES;

    }

}
Parthena answered 23/9, 2012 at 21:29 Comment(1)
Can you provide a small explanation?Prerogative
T
1

Your can also use scanners to solve this problem. The code is simpler and I think it also localized.

if (userIsInTheMiddleOfTypingANumber) {

    // Allow floating point numbers to be input. Malformed numbers are replaced by 0

    NSScanner *scanner = [NSScanner scannerWithString:display.text];
    double d;
    BOOL wellFormedDouble = [scanner scanDouble:&d];

    if (wellFormedDouble && [scanner isAtEnd]) {
        brain.operand=d;
    }
    else {
        brain.operand=0;
    }

    userIsInTheMiddleOfTypingANumber = NO;
}
Tour answered 22/7, 2011 at 20:26 Comment(0)
R
1

Hey I think I have a simple solution that works :)

- (IBAction)digitPressed:(UIButton *)sender
{
    NSString *digit = [[sender titleLabel] text];

    NSRange range = [[display text] rangeOfString:@"."];
    if (range.location != NSNotFound && [digit isEqual:@"."]) {
        return;
    }

    if (userIsInTheMiddleOfTypingANumber)
    {   
        [display setText:[[display text] stringByAppendingString:digit]];
    } 
    else 
    {   
        [display setText:[digit isEqual:@"."] ? @"0." : digit];
        userIsInTheMiddleOfTypingANumber = YES;
    }
}
Revulsive answered 26/7, 2011 at 15:59 Comment(3)
Thanks a lot! I figured it out by now, but my solution is indeed similar to yours. It took me a while to work out the whole idea around this. ThanksScraggy
Yeah I am doing part 2 of the assignment now... certainly a lot harder!Revulsive
Trying to do that aswell but it's hard :( Do you mind if I tweet you in case I have a question? :)Scraggy
S
1

I believe this is simpler.

- (IBAction)digitPressed:(UIButton *)sender
{ 
    NSString *digit =[[sender titleLabel] text];
    NSRange range =[[display text]  rangeOfString:@"."];
    if (([digit isEqual:@"."])&&(range.location==NSNotFound)){midtype=YES;}

    if (midtype){
    if (([digit isEqual:@"."])&&(range.location!=NSNotFound))       
         {[display setText:[display text]];}
    else {[display setText:[[display text]stringByAppendingString:digit]];}

    }
    else {[display setText:digit];
    midtype =YES;
}

}
Shinbone answered 14/10, 2011 at 3:40 Comment(0)
T
1

i saw that it suggests to add a function to handle the decimal after i started in on that bit, and ended up with this. the decimal flag is reset in operation pressed. and to really complete it, it should probably disallow leading 0's too.

if (userIsInTheMiddleOfTypingANumber) {
    if ([digit isEqual:@"."]) {
    if (!userIsInTheMiddleOfTypingADecimal) {
        [display setText:[[display  text] stringByAppendingString:digit]];
        userIsInTheMiddleOfTypingADecimal = YES;
    }
    }else {

    [display setText:[[display  text] stringByAppendingString:digit]];
    }
}
else//new number
{
    if ([digit isEqual:@"."]) {
        if (!userIsInTheMiddleOfTypingADecimal) {// this is a superfluous check as if it's a new number it is also not a decimal.

            [display setText:@"0."];
            userIsInTheMiddleOfTypingADecimal = YES;
            userIsInTheMiddleOfTypingANumber = YES;
        }
    }else {
    [display setText:digit];
    userIsInTheMiddleOfTypingANumber  = YES;
    }
}
Therese answered 3/12, 2011 at 20:48 Comment(0)
T
1

I found that I did not need to use NSRange. My code can do the operations beginning with a decimal number or a floating number.

-(IBAction)digitPressed:(UIButton *)sender
{
    NSString *digit = [[sender titleLabel] text];

    if(userIsInTheMiddleOfTypingANumber)
    {
        [display setText:[[display text] stringByAppendingFormat:digit]];
    }
    else
    {
        if([digit isEqual:@"."]) //check for the decimal and append to the digits
            [display setText:@"."];
        else
            [display setText:digit];

        userIsInTheMiddleOfTypingANumber = YES;
    }
}
Trinh answered 5/1, 2012 at 0:43 Comment(1)
but code must support only legal floating point numbers. So if you pres . twice it should be entered only once. So you should use NSRange.Monorail
M
1

I couldn't get any of the above code to work with the CS193P Fall 2011 Calculator. Here is how I finally got it to work.

-(IBAction)digitPressed:(UIButton *)sender
{ // Begin ACTION

    NSString *digit = sender.currentTitle;

    if (self.userIsInTheMiddleOfEnteringNumber) 
    {
        //Check to see if a decimal was entered
        if ([digit isEqual:@"."])
        {
            //Check to see if a decimal was entered before
            if (self.decimalEntered)
               {
                   [self Display];
               }
               else
                   {
                       self.Display.text = [self.Display.text stringByAppendingString: digit];
                       self.decimalEntered = YES;
                   }
        }
        else
        {
            self.Display.text = [self.Display.text stringByAppendingString: digit];
        }
    }  
    else 
    { 
        if ([digit isEqual:@"."])
        {
            //First Decimal Entered";
            self.Display.text = digit;
            self.decimalEntered = YES;
        }
        else
        {
            //First Number Entered";
            self.Display.text = digit;
        }
        // This tells the Brain that the user is typing      
        self.userIsInTheMiddleOfEnteringNumber = YES;
    }

} // End ACTION
Mast answered 5/2, 2012 at 0:9 Comment(0)
P
1

This is my first solution and doesn't look objective-C style but it works...

- (IBAction)digitPressed:(UIButton *)sender 
{
    NSString *digit = [sender currentTitle];
    if ([digit isEqualToString:@"."]) {
        self.numberOfDot ++;
    }
    if (self.userIsInTheMiddleOfEnteringANumber){
        if (self.numberOfDot < 2) {
            self.display.text = [self.display.text stringByAppendingString:digit]; 
        } 
        else
            if (![digit isEqualToString:@"."])
                self.display.text = [self.display.text stringByAppendingString:digit];   
    }
    else {
        self.display.text = digit;
        self.userIsInTheMiddleOfEnteringANumber = YES;
    }
}
Pitsaw answered 4/3, 2012 at 9:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.