Reputation: 5541
I have written a code which prints 1 if the number being tested is a happy number and 0 otherwise.
class Ishappy extends Thread {
private Integer num;
private Thread main;
private volatile boolean out = false;
Ishappy(int i, Thread main) {
this.main = main;
num = i;
}
void Exit() {
out = true;
}
@Override
public void run() {
while(!out && num != 1) {
if(num == 1) {
main.interrupt();
break;
}
String s = num.toString();
int temp = 0;
for(int i = 0 ; i < s.length(); i++) {
int x = Integer.parseInt(s.substring(i, i+1));
temp += x*x;
}
num = temp;
}
}
}
public class Happy_numbers {
public static void main(String[] args) {
byte path[] = null;
String s = "d:\\data.txt";
try(FileInputStream fin = new FileInputStream(s)) {
InputStreamReader in = new InputStreamReader(fin);
BufferedReader br = new BufferedReader(in);
s = br.readLine();
int num;
while(s != null) {
num = Integer.parseInt(s);
Ishappy ishappy = new Ishappy(num,Thread.currentThread());
ishappy.start();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println(1);
continue;
}
if(ishappy.isAlive()) {
ishappy.Exit();
System.out.println(0);
} else
System.out.println(11);
s = br.readLine();
}
} catch (FileNotFoundException ex) {
System.out.println("File not found.");
}catch(IOException ex){
}
}
}
but the above code always prints 11 for a happy number which means main
is never getting interrupted. Whats wrong??
The contents of data.txt are
1
7
22
Out of which 1 and 7 are happy numbers whereas 22 is not.
Upvotes: 0
Views: 1422
Reputation: 883
I don't see a need for threading here, a happy number is happy if the sum of its digits squared equals to one. if the sequence contains a number that is already tested. just terminate.
from wikipedia
If n is not happy, then its sequence does not go to 1. What happens instead is that it ends up in the cycle.
public class Happy_numbers {
static int[]SQUARES={0,1,4,9,16,25,36,49,64,81};
public static boolean is_happy(int n){
return is_happy(n, new HashSet<Integer>());
}
public static boolean is_happy(int n, Collection<Integer> sofar){
if(n==1) return true;
else if(sofar.contains(n)) return false;
sofar.add(n);
if(n<10) {
return is_happy(SQUARES[n], sofar);
}
char[]digits=String.format("%s", n).toCharArray();
int s = 0;
for(char c:digits){
s+= SQUARES[Integer.valueOf(String.format("%s", c))];
}
return is_happy(s, sofar);
}
public static void main(String[]args){
Collection<Integer> c1 = Arrays.asList(
1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97,
100, 103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208,
219, 226, 230, 236, 239, 262, 263, 280, 291, 293, 301, 302, 310, 313, 319,
320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376, 379, 383, 386, 391,
392, 397, 404, 409, 440, 446, 464, 469, 478, 487, 490, 496 );
Collection<Integer> c2 = new ArrayList<Integer>(c1.size());
long t = System.currentTimeMillis();
int c = 1;
for(int i=0;i<500;i++){
if(is_happy(i)) {
System.out.print(i+", ");
if(c++ % 20 == 0) System.out.println();
c2.add(i);
}
}
t = System.currentTimeMillis()-t;
System.out.println("\nTIME : " + t);
System.out.println("Got them all < 500 : " + (c2.containsAll(c1) && c1.containsAll(c2)));
}
}
It can be also further improved by using a map, or any caching technique so if a number is happy and you have calculated this number before, no need to do the same thing again. From wikipediea,
The happy numbers below 500 are: 1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97, 100, 103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208, 219, 226, 230, 236, 239, 262, 263, 280, 291, 293, 301, 302, 310, 313, 319, 320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376, 379, 383, 386, 391, 392, 397, 404, 409, 440, 446, 464, 469, 478, 487, 490, 496 (sequence A007770 in OEIS).
and the above code needs 435 to get all the happy numbers below 500.
1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97, 100,
103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208, 219, 226, 230, 236, 239, 262,
263, 280, 291, 293, 301, 302, 310, 313, 319, 320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376,
379, 383, 386, 391, 392, 397, 404, 409, 440, 446, 464, 469, 478, 487, 490, 496,
TIME : 435
Got them all < 500 : true
So, I have made some changes to your code to allow remembering what have been calculated so far, at least for the current number.
public class Happy_numbers {
static class Ishappy extends Thread {
private Integer num;
private Thread main;
private volatile boolean out = false;
private boolean unhappy = false;
Ishappy(int i, Thread main) {
this.main = main;
num = i;
}
public boolean isUnhappy() {
return unhappy;
}
void Exit() {
out = true;
}
@Override
public void run() {
Set<Integer> sofar = new HashSet<Integer>();
while(!out && num != 1) {
unhappy = sofar.contains(num);
if(num == 1 || unhappy) {
main.interrupt();
break;
}
sofar.add(num);
String s = num.toString();
int temp = 0;
for(int i = 0 ; i < s.length(); i++) {
int x = Integer.parseInt(s.substring(i, i+1));
temp += x*x;
}
num = temp;
}
}
}
public static void main(String[] args) throws Exception{
byte path[] = null;
String s = "./data.txt";
FileInputStream fin = new FileInputStream(s);
InputStreamReader in = new InputStreamReader(fin);
BufferedReader br = new BufferedReader(in);
int num;
while((s = br.readLine()) != null) {
num = Integer.parseInt(s);
Ishappy ishappy = new Ishappy(num,Thread.currentThread());
ishappy.start();
ishappy.join();
if(ishappy.isUnhappy()){
System.out.println("Number ["+num+"] is not happy");
}else{
System.out.println("Number ["+num+"] is happy");
}
}
br.close();
in.close();
fin.close();
}
}
and the output is
Number [1] is happy
Number [7] is happy
Number [22] is not happy
EDIT
I have found the reason why the main thread dosen't get interrupted.
in the main while loop, you check the num being 1 or not, if it was one, you wont get to the if condition that checks for the value of num and based on which interrupts the main thread.
public class Happy_numbers {
public static void main(String[] args) throws IOException{
String s = "./data.txt";
FileInputStream fin = new FileInputStream(s);
InputStreamReader in = new InputStreamReader(fin);
BufferedReader br = new BufferedReader(in);
int num;
while((s = br.readLine()) != null) {
num = Integer.parseInt(s);
Ishappy ishappy = new Ishappy(num,Thread.currentThread());
ishappy.start();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println(1);
continue; // here is another problem, infinit loop
}
if(ishappy.isAlive()) {
ishappy.Exit();
System.out.println(0);
} else
System.out.println(11);
}
br.close();
in.close();
fin.close();
System.out.println("DONE");
}
}
and here is Ihappy class
class Ishappy extends Thread {
private volatile Integer num;
private Thread main;
private volatile boolean out = false;
Ishappy(int i, Thread main) {
this.main = main;
num = i;
}
void Exit() {
out = true;
}
@Override
public void run() {
while(!out) { /// <- here was the problem
if(num.intValue() == 1) { // since this condition will break out
main.interrupt(); // of the loop, you do not need it in the
break; // while condition
}
String s = num.toString();
int temp = 0;
for(int i = 0 ; i < s.length(); i++) {
int x = Integer.parseInt(s.substring(i, i+1));
temp += x*x;
}
num = temp;
}
}
}
and the output is
1
1
0
DONE
Upvotes: 0
Reputation: 116918
As I read your program, the first time through the main loop, a new IsHappy
thread will be forked with num
set to 1
. In the IsHappy.run()
method, if num
is 1
it immediately quits.
while(!out && num != 1)
main
will sleep and then print 11
because the thread is no longer running.
if(ishappy.isAlive()) {
ishappy.Exit();
System.out.println(0);
} else
System.out.println(11);
Is that not what you expect? I think you should learn how to use a debugger. Here's a good tutorial on how to debug your program in Eclipse.
If the number 7
is processed then the IsHappy.run()
method will spin, setting num
to be 49
(7*7
) over and over. main
will then see that IsHappy
is still alive and will call IsHappy.Exit()
and will print 0
.
If the number 21
is processed then the IsHappy.run()
method will spin, setting num
to be 5
(2*2+1*1
) over and over. main
will again Exit()
the thread and print 0
.
So I guess your output is:
11
0
0
The main
thread will never be interrupted because the while
loop will stop it from running if num == 1
.
Couple of other comments about your code. THis may be test code so it doesn't matter but to be pedantic:
IOException
catch). At least put a comment in an empty catch block explaining why you don't care about the exception.Exit()
method should start with a lowercase letter. A better name for the method would be stop
.Upvotes: 1