Win a copy of Re-engineering Legacy Software this week in the Refactoring forum
or Docker in Action in the Cloud/Virtualization forum!

# Happy/unhappy numbers

Tom Cameron
Ranch Hand
Posts: 33
I'm seriously having problems with this. The problem is stated below.

Let the sum of the square of the digits of a positive integer S0 be represented by S1. In a similar way, let the sum of the squares of the digits of S1 be represented by S2 and so on. If Si = 1 for some i >= 1, then the original integer S0 is said to be Happy number. A number, which is not happy, is called Unhappy number. For example 7 is a Happy number since 7 -> 49 -> 97 -> 130 -> 10 -> 1 and 4 is an Unhappy number since 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4.

Input
The input file, called test.dat, will consist of several test cases, the number of which you are given in the first line of the input. Each test case consists of one line containing a single positive integer N.

Output
For each test case, you must print one of the following messages:

Case #p: N is a Happy number.
Case #p: N is an Unhappy number.

Here p stands for the case number (starting from 1). You should print the first message if the number N is a happy number. Otherwise, print the second line.

===== Sample input data =============================================
4
7
4
13
5
===== End of input data / Start of corresponding output data ========
Case #1: 7 is a Happy number.
Case #2: 4 is an Unhappy number.
Case #3: 13 is a Happy number.
Case #4: 5 is an Unhappy number.
===== End of output data ============================================

After all that, I managed to create the following code...

// happy numbers by Justin Tom

import java.io.*; // to get file input

public class Happynumbers {

public static void main(String args[]) {

try {
// read from the file test.dat

// defining variables
int n;
String input;
int casenumber = 1;

while ((input = comingin.readLine()) != null) {

// keep reading from test.dat line by line until there is nothing left to read
// note: incoming input is read line by line from test.dat as a string

n = Integer.parseInt(input); // converts string into integer

int sum = 0; // initialize the sum as zero when dealing with a number from the incoming data
int digit, x;

while (n>0)// loop as long as the original number is greater than zero
{
digit = n%10;// this will yield a single digit from the number
x = n/10;// divide the original number by 10 to remove the last digit
sum = sum + digit * digit;// the sum plus the square of its digit
}

x = sum;

if (sum == 1)
{ System.out.println("Case #" + casenumber + ": " + n + " is a Happy number."); // display the case number and the Happy number
casenumber++; // increment the casenumber
}

if (sum != 1 && casenumber != 1 )
{
System.out.println("Case #" + casenumber + ": " + n + " is an Unhappy number."); casenumber++; // display the case number and the Unhappy number
}

}}
catch (IOException e) // captures errors if any errors occur
{System.out.println(e); // display a message if an error occured
}}}

I tried putting in another while loop for taking the sum of the square of the digits but nothing will show up either. What did I do wrong? PLEASE FOR THE LOVE OF GOD HELP ME!!!

Tom Cameron
Ranch Hand
Posts: 33
I just realized that my problem lies in continually summing the square of the digits. It sounds simple but when I try to make a loop inside that while loop, it won't work. I think I got everything else in the program to work like I'm supposed to do. So, can someone please...... PLEASE help me???

Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
Nested looping can be hard to follow sometimes. The solution to help our brains out is often to break things up into more methods. Let's see if this helps:

So, a few things ...

1) Did it clarify things to break out the loops? Did you see the one I added? YOu have to keep looping through the sum of squares stuff until you find a reason to quit.

2) There are two reasons to quit. One is you hit 1 and have a happy number. The other is you do the sum of squares and get one you already had. That means the loop will run forever unless you're checking.

3) The trick of doing something like getNumber() before the loop and again in the loop is not the loveliest thing in the world but it's a practical thing to remember. In my COBOL days we caleld it a "primer read" to prime the pump and make a while condition work.

Tom Cameron
Ranch Hand
Posts: 33
Wow... you helped me so fast and quickly. It makes more sense to break it apart a bit more.

Thank you so much!!!

Justin

Tom Cameron
Ranch Hand
Posts: 33
um... after a bit of thorough thinking... I don't know how to put that all back into actual Java code... there's too many methods going on. Maybe a little bit more help please? ex. I don't understand that empty collection part. What am I supposed to type in that?

Tom Cameron
Ranch Hand
Posts: 33
I think I'm having more problems since I don't know how to break up the code into its own separate parts. I see how it works, but I'm not that familiar with the Java syntax yet. A tiny bit more help with that please?

Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
Sure. How are you learning Java? Do you have a book or instructor handy? Some of these basics are far easier to get if you have someone to visit with, but we can try on the ranch.

The stuff I wrote was not exactly Java. I left out the scope like public or private and the return types, so it was more a psuedocode sketch than real code. If you didn't know I was taking liberties like that it was probably pretty confusing.

You've probably made some of these:

This is a method like any other in Java. The only special thing about it is that when you run JavaC and tell it a class name, the JVM looks for a main method to run.

The "real" method signatures might be more like:

// No argument, returns the next int to work on
public int getNumber()

// One int argument, no return
public void tryOneNumber( int number )

// One int argument, returns another int
public int sumOfSquares( int number )

Take a shot at how you think the Java would look. We like to keep you doing the bulk of the work here at the Ranch. Go in very small steps to give yourself intermediate successes. For example, maybe just work out the getNumber() method.

Post some code to show us how it's going. That's the best way for us to see where you are stuck. Use the "CODE" button below the editor to preserve your indenting and spacing.

BTW: The "collection" business is making a place to keep the numbers you have tried. Look at Collection in the JavaDoc. Follow the links to Set and HashSet. JavaDoc: http://java.sun.com/j2se/1.5/docs/api/

Keep having fun! You're starting on a great journey!

Tom Cameron
Ranch Hand
Posts: 33
Alright. I split up the program and methods a bit more and revised it a little but I'm still having problems with solving the problem. This is what I have now:

import java.io.*; // to get file input

public class Happynumbers {

public static void main(String args[]) {

try {
// read from the file test.dat
// defining variables
int n;
String input;

while ((input = comingin.readLine()) != null) {

// keep reading from test.dat line by line until there is nothing left to read
// note: incoming input is read line by line from test.dat as a string

n(Integer.parseInt(input)); // converts string into integer

}}
catch (IOException e) // captures errors if any errors occur
{System.out.println(e); // display a message if an error occured
}
}
public static void n(int n1)
{
int originaln = n1;

int digit, x;
int casenumber = 1;

do {
int sum = 0; // initialize the sum as zero when dealing with a number from the incoming data

while (n1>0 )
{
digit = n1%10;// this will yield a single digit from the number
n1 = n1/10; // divide the original number by 10 to remove the last digit
sum = sum + digit * digit;// the sum plus the square of its digit

}

n1 = sum;

if (sum == 1) { break;}

if (sum == originaln) {break;}

if (sum == 1)
{
System.out.println("Case #" + casenumber + ": " + originaln + " is a Happy number."); // display the case number and the Happy number
casenumber++; // increment the casenumber
}

if (sum != 1 ) // as long as it is not the first case and the sum is not equal to one
{
System.out.println("Case #" + casenumber + ": " + originaln + " is an Unhappy number."); // display the case number and the Unhappy number
casenumber++;
}
}
while (n1 != originaln);
}
}

Tom Cameron
Ranch Hand
Posts: 33
Oh yea, Stan, I'm a high school student and I'm currently learning Java at school.

venkatesh pendharkar
Ranch Hand
Posts: 106
Hi try running this code,i hv tried to rewrite it:

import java.io.*;
class HappyNumber
{
public static void main(String[] args) throws IOException
{
try
{
int n; // defining variables
String input;
// keep reading from test.dat line by line until there is nothing left to read
// note: incoming input is read line by line from test.dat as a string
int counter=0; //this counter corresponds to the case number
while ((input = comingin.readLine()) != null)
{
Calc1(Integer.parseInt(input),counter); // converts string into integer
counter++;
}
}
catch (IOException e) // captures errors if any errors occur
{
System.out.println(e); // display a message if an error occured
}
}

static void Calc1(int n,int c)
{
int caseno=c;
int originalno=n;
int sum=0;

while (!(sum==1||sum==originalno)) //the method will stop doing the
//summing unless sum=1 or sum=original no
{
n=Calc2(n); //call the Calc2 method to calculate the sum of squares of digits
sum=n;
}
//printing the result
if (sum==1)
{
System.out.println("Case#"+caseno+":"+originalno+"is a Happy Number");
}
else
{
System.out.println("Case#"+caseno+":"+originalno+"is a Not a Happy Number");
}
}

//this method will calculate the sum of squares of digits of any no & will return the value
static int Calc2(int a)
{
int digit;
int s=0;
while (a>0)
{
digit = a%10; // this will yield a single digit from the number
a= a/10; // divide the original number by 10 to remove the last digit
s = s + digit * digit; // the sum plus the square of its digit
}
return s;
}
}

venkatesh pendharkar
Ranch Hand
Posts: 106
In this code i hv used test.txt instead of test.dat

Tom Cameron
Ranch Hand
Posts: 33
I must say... just WOW! That's an ingenious idea to make a method that will "return" a value of the sum. I looked up why you didn't put a "void" there when you made that last method. And appearantly, it returns a value back to Sum 2 and then you used that and then by recalling from the numbers coming in. Then the numbers won't keep on looping forever when I *cough* "tried" to take the square of the digits of the number. And and... ... given the right conditions it'll pass through or not (if it is an unhappy number and if it's the first number going through the program, it's ignored), it all works soooo PERFECTLY!!! I think I actually understand it inside and out!!! Thank you venkatesh pendharkar and Stan James!!! You won't believe how many hours/days I've spent on this. (one night, I dreamt that I was trying to program this, and then the loop went on forever and the computer caught on fire )

Thank you guys!!!

Warmest wishes and thanks,
Justin Tom

Tom Cameron
Ranch Hand
Posts: 33
lol, another question arose.

you rewrote my while condition to this:

while (!(sum == 1 || sum == originalno)) //the method will stop doing the
//summing unless sum=1 or sum=original no

in the code three posts up from this one.

Now why is the ! ("not" symbol) thingie is outside of the inner brackets? shouldn't it be

while (sum != 1 || sum != originalno)

or is that just saying the same thing with a matter of difference in style of writing the code?

Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
Hey, it's great fun to have a HS student on the path here. Sounds like you're keeping it fun.

Here's something I learned as DeMorgan's Theory in Boolean Algebra but I think that DeMorgan covers a lot more rules. Google and see Anyhow:

not ( a or b ) == ( not a and not b )
not ( a and b ) == ( not a or not b )

so

!(sum == 1 || sum == originalno) == ( sum != 1 && sum != originalno )

Sometimes you have to put this stuff in English. Either Sum == OR sum == original is sufficient to make you stop. So to keep going sum can't be 1 AND it can't be original.

Which form is clearer is probably personal. If things get much more complicated than this I try to break it into smaller chunks again.

Tom Cameron
Ranch Hand
Posts: 33
ah... I've seen those rules before. Now that's neat! And yes programming is fun but can be frustrating if I can't get something to work after so many days. lol... sorta like calculus. Getting off topic, thanks guys.

Thanks

Tom Cameron
Ranch Hand
Posts: 33
ok, something is seriously seriously wrong now. I know, I know, I keep coming up with more problems and ruining the happy moods. I'm killing myself here.

In your revised code of mine, it does not output anything beyond 4 numbers. Example, if test.txt had

4
7
4
13
5

the program outputted

Case#0:4is a Not a Happy Number
Case#1:7is a Happy Number
Case#2:4is a Not a Happy Number
Case#3:13is a Happy Number

Since number 4 is not a happy number and it is the first case, it shouldn't be displayed, as described in my very first post. And second, anything beyond the fourth number, in this case, the number 5 is not displayed at all. I read your code over and over again and it "seems" perfect...? and it can't be about anything about cutting off any unhappy numbers after the last happy number since I just tried ending it with another happy number 13 and it still doesn't work. Weird? I tried to revise it again and now I'm having more problems... lol...seriously, will the original problem be solved? I tried adding more comments to help myself and maybe to help explain what's going on in my code.

Tom Cameron
Ranch Hand
Posts: 33
What the heck?

In my new code, it's output was:

Case#2: 7 is a Happy Number
Case#3: 4 is an Unhappy Number
Case#4: 13 is a Happy Number

and the input file test.dat was:

4
7
4
13
5
13

Help again!!! I thought it was solved!!! ( and yes I tried fixing it, and I really should be doing other homework but this is the better kind of work)

venkatesh pendharkar
Ranch Hand
Posts: 106
the problem that u r saying i.e. the code calculates output only 1st 4 lines of input is wrong,If you write number 7 in 1st 10 lines of the test file then code will calculte all the 10 lines.But the problem comes if u write numbers like 5 ,8 or 2 in the input.The compiler is not able to find wheather the no is happy or not coz this nos dont give the result sum to be 1 or original no in few iterations.If you want to chk the sum,U can write System.out.println(sum) in Calc1 method & see the sum.You will also see that for these numbers when u run this program,it doesn end & keeps on running.

Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
Cool progress!

Here's where we need that collection to keep track of all the numbers we have tried so far. If any of them shows up again then the pattern will repeat forever. Here's the sequence for 5. What happens next?

5 25 29 85 89 145 42 20 4 16 37 58 ...

BTW: Why are you checking for case #1?
[ May 02, 2006: Message edited by: Stan James ]

venkatesh pendharkar
Ranch Hand
Posts: 106
Now as you have mentioned for the number 5 u get:5 25 29 85 89 145 42 20 4 16 37 58 ..if this is continued then next nos are58 89 145 42 20 4 16 37 58
89 145 42 20 4 16 37 58 89 145 42 20 4 16 37 58 89 145 42 20 4 ...
thus after the sum becums 4 then 4 16 37 58 89 145 42 20 4 these nos keep repeating as we know that 4 is an Unhappy no i.e.Si=original number
Hence the for 5 the the sum never bcums equal to 1 or 5 itself i.e.compiler keeps moving between 4 16 37 58 89 145 42 20 4 ,this also happens for other nos like 8, 6 becuase at some point the sum bcums 4 & hence compiler keeps running between the value of 4.i.e.4 16 37 58 89 145 42 20 4
I didn get you why y asked that "why r u taking case#1?"

Ryan McGuire
Ranch Hand
Posts: 1055
4
Originally posted by venkatesh pendharkar:
...
I didn get you why y asked that "why r u taking case#1?"

He asked that question because it is an unnecessary check. If you keep track of all the numbers produced and stop when a duplicate is made, the loop will terminate sooner or later for any number. You don't really need to make Si==1 a special case. You need to keep track of what the repeat number is to determine the happy/unhappy status of the original number, but you don't really need to check for 1 specifically.

And, if I understand correctly, the reason venkatesh added that test is because that's how the problem is stated. Specifically, if Si==1 there is no reason to calculate S(i+1) -- as soon as Si is 1 we can exit the loop and call S0 Happy.

...or am I stating the obvious?

Ranch Hand
Posts: 31
Hi guys,
As some of you said, the loop should stop when you hit 1, which means that you have a happy number.But, the other condition should be that you went back to any of the numbers already tried, not necessarily case#1.Because, as you can see from tryin with number 5, the loop would enter a closed cycle once it hits 4.
I suggest that you keep track of all the numbers already tried, something like:
while((n!=1) && !(list.contains(n)))
I used an ArrayList for that and it works perfectly.
Good luck to everyone!

Ranch Hand
Posts: 31
Hey, it turned out it's not easy being a number at all.
Only 20 of the first hundred ones are Happy, and it gets even worse after that!!!

Tom Cameron
Ranch Hand
Posts: 33
um... too much logic. Thanks for telling me to output the sum! It looked scary, with all those numbers across the screen... And it's not as easy as I originally thought it was... I've looked at my classmate's solution and he just broke down the number into 5 digits and then determined if it was a happy number or not. His solution was limited to a number with 5 digits. Another solution limited theirs by recording all the possible unhappy numbers and escape the loop if the sum became an unhappy number (used a loop), and that seems just WAY TOO inefficient!!!

Well, what if I recorded the number of steps it took to find the sum and then limit the number of steps? Maybe I could limit the number of steps to 1000?

ex.
4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> ... and so it will never reach one but it'll EVENTUALLY have to be terminated since I limited it to 1000 steps.

Now I rewrote my code by adding another method to keep the count of the number of steps:

The "new" problem: I tried keeping track of the number of steps it takes to sum up the square of the digits but something isn't right with my code, as it ruined my output. I outputted x and all I got was 1's and 2's and occassionally a 3... I need help with that.

Btw: that thingie about that extra case number 1 condition, I kept it in there because if and only if the first case is unhappy, ignore it and print out the next line (as stated in the original problem). Hopefully that'll clarify what I tried to do.

I'm chewing off more than I can bite. More help plz?
(Java code and the logic behind this would help a lot)
(more people the better )

Tom Cameron
Ranch Hand
Posts: 33
I thought about trying to keep track of the numbers that are used, but then the array would eventually become way too big (stack overflow !!!). I wanna try this new method of mine to keep track the number of steps to sum up the square of the digits. That way, instead of limiting the number of digits I can have, I'm making the computer the limit of how much it can handle . Look in the last 2 methods in my code in my post above this one. I need help there to keep count of the steps so I can get out of the unhappy loop, because it's wrong and screwed up my output. HELP!

Stefan Wagner
Ranch Hand
Posts: 1923
Originally posted by Justin Tom:
I thought about trying to keep track of the numbers that are used, but then the array would eventually become way too big (stack overflow !!!).

Well - how big is your stack? Do you know?
How many numbers could be put into the array?

The CalculateSquares method returns a bigger value for 99 than 100, because 9*9=81 => 2*81 > 1+0+0.
The biggest Integer is made of 10 digits, starting with 21.
The biggest number calculated by the method has to be 1 999 999 999.
To estimate the result I replace lazily 9 with 10, and get 10*10=100 for each 9 which is 901 in total.
So we know that the biggest number in step 2 is below 901 - let's assume it is 899.
That will return (lazily calculated) 100*3 which is 300.
No number bigger than 1000 will be calculated from an Integer.

So adding those numbers to a Set is no problem, while stopping recalcalculation after 1000 steps isn't false.

Tom Cameron
Ranch Hand
Posts: 33
Now what would the Java code look like if I were to keep track of those number of steps? I tried typing it into my code but it doesn't seem to be right. I don't want to use stacks (mostly because I'm 80% unfamiliar with the Java code dealing with stacks, but i do know how to declare arrays).

Ranch Hand
Posts: 31
Hi Justin,
I didn't quite get the reason why u r using counter?
But, all this code:

could be replaced by:

You still didn't address the real problem, which is breaking out of the loop when you encounter a number for the second time.Instead of encountring the original number, which will not always happen(for example when the original number is 5).
You could use ArrayList because, unlike arrays, you don't have to know before hand the size of your arraylist and they have a convenient method to add more objects and a more convenient one to check if an arraylist contains a certain value.
You could take a look at the code that I came up with if you want. I used a totally different approach.And instead of getting the input from a file, this program just prints out the happy numbers between 1 and 1000.

Good luck!

Tom Cameron
Ranch Hand
Posts: 33
You're right Samir, I didn't break out of the loop. So then, I used another solution. My instructor gave me a really great idea by looking for patterns and I found one in the Unhappy numbers. Every unhappy nummber I encountered (by hand and then by the program and then double checking again by hand) is that the sum was always became: itself, or 4, or 83 but always have the sum == 1 case override that. So I used those conditions to break out of the loop and now I FINALLY completed the solution 100%, failproof and I fixed the case numbering too. You guys REALLY helped me a lot!!!

My finalized code (hopefully no more errors, but I seriously don't see any left) :

Thank you guys so much! Especially in the beginning when I struggled and you guys helped! (yes!!! I avoided stacking and the use of arrays ) And the best part is that you guys helped me with the code following it my way!

Hugs and thank you's!

Justin Tom
P.S. I'll still be back, maybe in other topics unless I find another error or if you guys see another error... lol... but I think it's pretty much "fail-proof" since it works for all conditions.

Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791

I thought about trying to keep track of the numbers that are used, but then the array would eventually become way too big (stack overflow !!!).

I tried this from 0 to 500,000 and the longest chain of tries was 20 for 15,999. All of my happy numbers terminated in 6 or less. I was rather surprised at that!

[ May 03, 2006: Message edited by: Stan James ]

Tom Cameron
Ranch Hand
Posts: 33
interesting... now I'm surprised too!!! I wonder if that limit (the biggest maximum number) for determining happy/unhappy numbers would be the same for me and or every other solution...? And now I wonder if Java capped the largest calculatable number?