Wednesday, December 28, 2011

Program to Determine the Ordinal Value of a Number

Problem:
Like most other languages, English include two types of numbers: cardinal numbers (such as one, two, three, and four) that are used in counting, and ordinal numbers (such as first, second, third, and fourth) that are used to indicate a position in a sequence. In numeric form, ordinals are usually indicated by writing the digits in the number, followed by the last two letters of the English word that names the corresponding ordinal. Thus, the ordinal numbers first, second, third, and fourth often appear in print as 1st, 2nd, 3rd, and 4th.
The general rule for determining the suffix of an ordinal can be defined as follows:
Numbers ending in the digit 1, 2, and 3, take the suffixes "st", "nd", and "rd", respectively, unless the number ends with the two- digit combination 11, 12, or 13. Those numbers, and any numbers not ending with a 1, 2, or 3, take the suffix "th".
Your task in this problem is to write a function ordinalForm(n) that takes an integer n and returns a string indicating the corresponding ordinal number.  (Roberts ch 10, problem 9).


What it looks like:

/* File: ordinalForm.java
 * -----------------
 *This console program lets the user enter in any integer and will print out the ordinal form of that number. For example
 *the ordinal form of 1 is "1st," 2 is "2nd" etc. The user enters the sentinel value "-1" to stop running the program.
 *
 *The program and the method of the same name takes an integer as the entered value and returns a string. We use the ACM library's (?)
 *built-in Integer class and its toString method. Because the suffix of an ordinal value depends on the last digit
 *of a number our program has to strip out and inspect the last digit of the supplied integer so we use the method 
 *"getLastDigit" to inspect the last digit. In the case of numbers ending with "11", "12" and "13" we need to see the last
 **two* digits so we also use a similiarly-constructed getSecondToLastDigit.
 */
import acm.program.ConsoleProgram;
public class ordinalForm extends ConsoleProgram {
    public void run() {
       while (true){
       int cardinal = readInt("Enter number and we'll give you the ordinal form: ");
       if (cardinal == -1){
           break;
       }
       print(makeOrdinal(cardinal));
       }
    }
    private String makeOrdinal(int n) {
        String ordinal = "";
        int lastDigit = getLastDigit(n);
        int secondToLastDigit = getSecondToLastDigit(n);
        if ((lastDigit == 1) && secondToLastDigit !=(1)){
            ordinal = Integer.toString(n) + "st"; //Not sure why it's "Integer.toString(n)" instead of "n.toString" or "toString(n)"
        }
        else if (lastDigit ==2 && secondToLastDigit !=(1)) {
            ordinal = Integer.toString(n) + "nd"; 
        }
        else if (lastDigit == 3 && secondToLastDigit !=(1)) {
            ordinal = Integer.toString(n) + "rd";
        }
        else ordinal = Integer.toString(n) + "th";
        return ordinal;
    }
    private int getLastDigit(int n) {
        int remainder = n % 10;
        return remainder;
    }
    
    private int getSecondToLastDigit(int n) {
        int remainder = 0;
        for (int i = 0; i < 2; i++){
            remainder = n % 10;
            n /= 10;
        }
        return remainder;
    }
}
}








What made it tricky:


My first version of this was running just fine....it just kept returning the wrong answer. Have a look at this sample run when the bug existed and guess what the problem was:



Here's a clue: this is what my private methods getSecondToLastDigit(n) and getLastDigit(n) looked like:

    private int getLastDigit(int n) {
        int remainder = 0;
        while (n > 0) {
            remainder = n % 10;
            n /= 10;
        }
        return remainder;
    }

    private int getSecondToLastDigit(int n) {
        int remainder = 0;
        while (n > 10) {
            remainder = n % 10;
            n /= 10;
        }
        return remainder;
    }
So while getLastDigit(n) should have just divided by n *once* and returned the remainder, instead it kept dividing by n until there was nothing left. So it was really stripping off and returning the *first* digit, not the last! getSecondToLastDigit(n) was behaving the same way, except it stopped one iteration sooner so it returned the second digit, not the second-to-last. Ugh, so embarrassing, blame it on the Christmas food abundance.

I didn't see the pattern or understand what was wrong for a while so I made this quick debugging program that printed out the results of just getLastDigit(n):

import acm.program.ConsoleProgram;
public class testLastDigit extends ConsoleProgram {
    public void run() {
       int n = readInt("Enter an int and we'll give you the last digit");
       print (getLastDigit(n));
    }
    private int getLastDigit(int n) {
        int remainder = 0;
        while (n > 0) {
            remainder = n % 10;
            n /= 10;
        }
        return remainder;

    }
}
I ran it a bunch of times and saw that indeed, testLastDigit  was giving me the wrong answer. Once I saw that it was wrong and predictably wrong, the fix was easy.


10 comments:

  1. First off I would like to say wonderful blog! I had a quick question which I'd like to ask if you do not mind. I was curious to know how you center yourself and clear your mind prior to writing. I've had difficulty clearing my thoughts in getting my thoughts out
    there. I do enjoy writing however it just seems like
    the first 10 to 15 minutes are lost just trying to figure out
    how to begin. Any suggestions or tips? Many thanks!

    My homepage: Candy Crush Saga Hack

    ReplyDelete
  2. Definitely believe that which you said. Your favourite reason seemed to be on
    the web the easiest thing to be aware of. I say to you, I definitely get irked whilst other
    people think about worries that they plainly don't know about. You managed to hit the nail upon the top as neatly as outlined out the entire thing with no need side effect , other people could take a signal. Will probably be again to get more. Thank you

    Also visit my site - pirater un compte facebook

    ReplyDelete
  3. This post is genuinely a fastidious one it assists new internet visitors,
    who are wishing for blogging.

    Also visit my page - psn Code Generator

    ReplyDelete
  4. I couldn't refrain from commenting. Well written!

    Feel free to surf to my blog; Psn Code Generator

    ReplyDelete
  5. This is a topic that's near to my heart... Many thanks! Where are your contact details though?

    Feel free to visit my webpage World Of Tanks Hack

    ReplyDelete
  6. Do you mind if I quote a couple of your posts as long as I provide credit and sources
    back to your website? My blog is in the very same niche as yours and my
    visitors would definitely benefit from a lot of the information you provide here.
    Please let me know if this okay with you. Thanks!

    Also visit my blog post: download 7zip ()

    ReplyDelete
  7. What's up to all, how is everything, I think every one is getting more from this site, and your views are nice designed for new visitors.

    Also visit my web site ... how To jailbreak Ps3

    ReplyDelete
  8. My family members always say that I am killing my time here at web, but I know I am getting experience everyday by reading such nice
    content.

    Feel free to visit my page; best gas grills 2014

    ReplyDelete
  9. Hi there, I believe your web site might be having web browser compatibility problems.

    Whenever I take a look at your web site in Safari, it looks fine
    however, if opening in I.E., it has some overlapping issues.
    I just wanted to give you a quick heads up! Besides that, wonderful blog!


    Here is my weblog - seo consultant in 90 days (carsanoba.co.kr)

    ReplyDelete
  10. It's fantastic that you are getting thoughts from this post as well as from
    our argument made here.

    ReplyDelete