Head First Java Puzzle4 (Chapter 4, pg 91) Explanation - java

Below is the solution to, and output of,the subject puzzle, and I'm having trouble understanding how it works.
public class Puzzle4 {
public static void main(String[] args) {
Puzzle4b[] obs = new Puzzle4b[6];
int y = 1;
int x = 0;
int result = 0;
while (x<6) {
obs[x] = new Puzzle4b();
obs[x].ivar = y;
y = y*10;
x = x+1;
}
x = 6;
while (x>0) {
x = x-1;
result = result + obs[x].doStuff(x);
}
System.out.println("result " + result);
}
}
class Puzzle4b {
int ivar;
public int doStuff(int factor) {
if (ivar>100) {
return ivar*factor;
} else {
return ivar*(5-factor);
}
}
}
Output:
result 543345
From my understanding, the first While loop will run through 6 times (from x==0 to x==5). The y variable, and in turn 'ivar', will have a value of 1,000,000 (I think this is where I'm going wrong, but I'll continue in hopes of being corrected).
The second While loop is a bit confusing to me. It'll run through 6 times, with the second line of the loop passing the 'x' values to the doStuff method for it to return a value. The numbers I'm coming up with for the result don't match the actual result.
Any help here would be appreciated. Please let me know if I'm thinking about it the wrong way. If someone wants to reformat my code to align more closely with industry standards, it would be great to learn good habits from the start!

this piece of code `
obs[x].ivar = y;
y = y*10;
will cause first ivar = y = 1 then multiple y
so it'll be {1 - 10 - 100 - 1,000 - 10,000 - 100,000}
the second loop x will be { 5 , 4 , 3 , 2 , 1 , 0 }
so it'll start like this result = result+obs[5].doStuff[5];
i guess all the misunderstanding that x in element 1 will equal y in element 5
and x in element 2 will equal y in element 4 and so on " because x is incrementing and y is decrementing
so it will go like this
(ivar > 100 )
ivar * (5-factor)
x[3] * y[2] = 1000 * (5-2) = 3000
x[4] * y[1] = 10000 * (5-1) = 40000
x[5] * y [0] = 100000 * (5-0) = 500000
then (ivar < 100)
ivar * factor
x[1] * y [5] = 1 * 5 = 5
x[2] * y [4] = 10 * 4 = 40
x[3] * y [3] = 100 * 3= 300
then if you add all the numbers together you'll have your output

In the second while loop,
while(x>0) will give 543340
Instead While (x>=0) should give the required output
If I'm not wrong

For me an easy way to break this down is stepping through and seeing exactly where the values are coming from. I've done this below and commented it into the code.
public class Puzzle4 {
public static void main(String[] args) {
Puzzle4b[] obs = new Puzzle4b[6];
int y = 1;
int x = 0;
int result = 0;
// let's break out of the loops
obs[0] = new Puzzle4b();
obs[0].ivar = 1;
obs[1] = new Puzzle4b();
obs[1].ivar = 10;
obs[2] = new Puzzle4b();
obs[2].ivar = 100;
obs[3] = new Puzzle4b();
obs[3].ivar = 1000;
obs[4] = new Puzzle4b();
obs[4].ivar = 10000;
obs[5] = new Puzzle4b();
obs[5].ivar = 100000;
// ivar's = 1, 10, 100, 1000, 10000, 100000
result = result + obs[5].doStuff(5); // 0 + (5 * 100000)
result = result + obs[4].doStuff(4); // 500000 + (4 * 10000)
result = result + obs[3].doStuff(3); // 540000 + (3 * 1000)
result = result + obs[2].doStuff(2); // 543000 + ((5 - 2) * 100)
result = result + obs[1].doStuff(1); // 543300 + ((5-1) * 10)
result = result + obs[0].doStuff(0); // 543340 + ((5-0) * 1)
// result = 543345
}
System.out.println("result " + result);
}
}
class Puzzle4b {
int ivar;
public int doStuff(int factor) {
if (ivar>100) {
return ivar*factor;
} else {
return ivar*(5-factor);
}
}
}
Hope this has helped you understand the example.

The key is to understand what each loop does.
1st one is nothing but just assigning values to ivar variable of each array object. You do it with "x" value as index.
2nd one you still get indices from what "x" variable currently is. And then you need to remember what ivar value is for exactly this index. With that in mind you will be able to understand what condition of doStuff method is true and what expression you should use respectively.
Also, you have to remember of what value "result" variable get on each loop iteration. Like 1st iteration result = 500 000. then 2nd one will be result = 500 000 + doStuff.
And last but not least, not without reason the book calls you to do exercises on paper. It leads to a lot of writing but also to understanding what code does on each and every line.

Related

Flipping a coin and stopping when it lands heads 4 times in a row

The assignment is to flip a coin until four heads in a row are seen and display all the results leading up to that. I keep getting the last error message I put in just in case it fell through. I have no idea what I messed up and was wondering if someone was able to help.
class Main {
public static void main(String[] args) {
int h = 2;
int t = 1;
int count = 0;
int result;
while (count<=4)
{
result = (int)Math.random()*2;
if (result == 2)
{
count++;
System.out.print("H ");
}
else if (result == 1)
{
count=0;
System.out.print("T ");
}
else
System.out.println("error");
}
}
}
(int)Math.random() * 2
is the same as
((int)Math.random()) * 2
Given that Math.random() returns a number at least zero but less than one, your expression is always going to be zero.
Put in parentheses:
(int) (Math.random() * 2)
But then, also look at the values of result in your conditionals: you will never generate 2.
You need to add 1 to have possible values of one or two:
result = (int) (Math.random() * 2 + 1);
You can use the Randomclass and boolean
Random random = new Random();
int count = 0;
while (count < 4) {
if (random.nextBoolean()) {
System.out.print("H");
count++;
} else {
count = 0;
System.out.print("T");
}
}
As the result of Math.random() is between 0 and 1 type casting it to int will remove the digits after decimal point and you'll always have zero as answer.
Below code will help you to generate a random number between min and max.
// define the range
int max = 2;
int min = 1;
int range = max - min + 1;
int rand = (int)(Math.random() * range) + min;
For an explanation of how this works you can put the min possible value of 0 and max possible of 0.99 and multiply both by any range, let's say 20 the answer will still be in between 1 to 20.8 which gets turned to 20 as it's not rounding off but directly type casting. Hence, this can give you a random number for any range.

How to write a Taylor series as a function

I have to write a Taylor series until the 16th element that calculates sin and compare the values returned values with Math.sin. Well , everything works fine until the last time when instead of 0.00000 i get 0.006941.Where is my error and if somebody have an idea how to write this in a more professional way I would be very happy.
import java.text.NumberFormat;
import java.text.DecimalFormat;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
NumberFormat formatter = new DecimalFormat("#0.000000");
double val[] = {0, Math.PI / 3, Math.PI / 4, Math.PI / 6, Math.PI / 2, Math.PI};
for (int i = 0; i < val.length; i++) {
System.out.println("With Taylor method: " + formatter.format(Taylor(val[i])));
System.out.println("With Math.sin method: " + formatter.format(Math.sin(val[i])));
}
}
public static double Taylor ( double val){
ArrayList<Double> memory = new ArrayList<Double>();
double row = val;
for (int i = 0, s = 3; i < 16; i++, s = s + 2) {
double mth = Math.pow(val, s);
double result = mth / factorial(s);
memory.add(result);
}
for (int i = 0; i < 16; i++) {
if (i % 2 == 0) {
double d = memory.get(i);
row = row - d;
} else {
double d = memory.get(i);
row = row + d;
}
}
return row;
}
public static long factorial ( double n){
long fact = 1;
for (int i = 2; i <= n; i++) {
fact = fact * i;
}
return fact;
}
}
Your math is correct, but your factorials are overflowing once you get to calculating 21!. I printed out the factorials calculated.
factorial(3) = 6
factorial(5) = 120
factorial(7) = 5040
factorial(9) = 362880
factorial(11) = 39916800
factorial(13) = 6227020800
factorial(15) = 1307674368000
factorial(17) = 355687428096000
factorial(19) = 121645100408832000
factorial(21) = -4249290049419214848 // Overflow starting here!
factorial(23) = 8128291617894825984
factorial(25) = 7034535277573963776
factorial(27) = -5483646897237262336
factorial(29) = -7055958792655077376
factorial(31) = 4999213071378415616
factorial(33) = 3400198294675128320
It appears that your raising val to ever higher powers isn't significant enough to make a difference with the overflow until you get to the highest value in your array, Math.PI itself. There the error due to overflow is significant.
Instead, calculate each term using the last term as a starting point. If you have the last value you entered into memory, then just multiply val * val into that value and then divide the next two numbers in sequence for the factorial part.
That's because memory.get(i) is equal to memory.get(i - 1) * (val * val) / ((s - 1) * s). This also makes your calculation more efficient. It avoids the multiplication repetition when calculating the numerator (power part) and the denominator (the factorial calculation). This will also avoid the overflow which results from how you calculated the denominator separately.
My implementation of this idea substitutes this for the first for loop:
double mth = val;
for (int i = 0, s = 3; i < 16; i++, s = s + 2) {
mth = mth * val * val;
mth = mth / ((s - 1) * s);
memory.add(mth);
}
and places
double row = val;
between the for loops, to ensure that the first term is the initial sum as you had it before. Then you don't even need the factorial method.
This this I get 0.000000 for Math.PI.

finding the sum of the sreies, using java

the question is to find the sum of this series
series
i used this code to solve it , but im not quite sure the logic is correct.
the noofterms is how many terms are going to be added
and x is the number that will be assigned to the variable.
does the logic seem correct?
public static double sumOfSeries(double x, int noofterms){
double evennumbers=1;
double oddnumbers=1;
double result=1;
// since the power of x starts from 1 , we start i from 1 and increment by 2
for (int i=1; i<noofterms; i+=2 ){
// we reset starting numbers so we start from them everytime
evennumbers = 1;
oddnumbers = 1;
// everytime the number increases by 2 when it is smaller than i+1
// ex when its equal to 2 , j = 3 , j+1 = 4 so it increments by 2
// when its 4 , j = 5 , j+ 1 = 6 , it increments
for (int j=2; j<=i+1; j+=2){
// multiply by increments of 2
evennumbers= evennumbers * j;
}
// it starts from 1 and increments by 2 so it goes like 1,3,5
for (int z=1; z<=i; z+=2){
oddnumbers = oddnumbers * z;
}
result*=((Math.pow(x, (double)i)) / (double)i) + (oddnumbers/evennumbers);
}
return result;
}
You can do it better. Note that numerators and denominators form two sequences, so you can keep previous terms to efficiently make computations, this will look like this :
long even = 1;
long odd = 1;
double result = x;
for(long i = 1; i < noofterms; i++)
{
even *= 2 * i;
odd *= 2 * i - 1;
double oper = Math.pow(x, (double)(2 * i + 1)) / (double)(2 * i + 1);
result += (double)even / (double)odd * oper;
}
You can improve by using logarithms because even and odd will grow very fast and will lead to overflows :
double even = 0.0;
double odd = 0.0;
double result = x;
double logx = Math.log(x);
for(long i = 1; i < noofterms; i++)
{
even += Math.log((double)(2 * i));
odd += Math.log((double)(2 * i - 1));
double oper = logx * (2 * i + 1) - Math.log((double)(2 * i + 1));
result += Math.exp(even - odd + oper);
}
EDIT: only one sequence could also be computed : p *= (double)(2*i)/(2*i-1). Then the log trick is not useful.

Trying to add a sum of first consecutive odd squares?

I'm trying to add a sum of consecutive odd squares to add up to the same number. For example: the first 4 consecutive odd square numbers added together will equal 84, (1*1) + (3*3) + (5*5) + (7*7) = 84. The Attached is my code. Result 2, the non-loop code, is correct. I need help on resolving what I'm doing wrong with result1's loop code.
Inputnumber equals the number of odd squares requested.
public static int sumWithLoop (int inputNumber)
{
int result1 = 0;
int counter = 1;
while (counter <= inputNumber)
{
result1 = result1*result1 + counter;
counter = counter + 2;
}
return result1;
}
public static int sumWithoutLoop (int inputNumber)
{
int result2 = (inputNumber*(2 * inputNumber - 1) * (2 * inputNumber + 1) / 3);
return result2;
}
You probably meant result1 = result1 + counter * counter; instead of result1 = result1*result1 + counter;.
Most of your problem is in the math inside the while loop.
result1 should be initialized to 1. (At least the way I'm doing it.)
Your first line in the block squares result1 and adds counter to it. What you need is something more like this:
result1 = result1 + (int) (Math.pow(1 + 2 * counter, 2));
This takes result1 and adds the next odd square to it. (1 + 2 * counter = the next odd number)
With the above code to determine the next odd number, counter should be incremented by 1 at the end of the while loop, rather than 2 (because I multiply counter by 2 in the Math.pow function).
My final code looks like this:
public static int sumWithLoop (int inputNumber)
{
int result1 = 1;
int counter = 1;
while (counter < inputNumber)
{
result1 = result1 + (int) (Math.pow(1 + 2 * counter, 2));
counter = counter + 1;
}
return result1;
}
It returns 84 when inputNumber is 4, 165 when it's 5, 286 when it's 6, etc., so it looks like it works.
Hope this helped!
P.S. Just FYI, I/you could have used result1 += (int) (Math.pow(1 + 2 * counter, 2)); in the first line in the while loop. The difference is the += operator, which adds the following value to the preceding variable. It's more concise than this = this + somethingMore;
Also, in the second line, we could've used counter++;, instead of counter = counter + 1; ++ adds one to the variable it's used on.

I have some questions regarding this tracing

public class Task {
public static void main(String args[]) {
int x = 0, p = 0, sum = 0;
p = 1;
x = 2;
double q;
sum = 0;
while (p < 12) {
q = x + p - (sum + 5 / 3) / 3.0 % 2;
sum = sum + (x++) + (int) q;
System.out.println(sum);
if (x > 5)
p += 4 / 2;
else
p += 3 % 1;
}
sum = sum + p;
System.out.println(sum);
}
}
While proceeding to line 12 (sum = sum + (x++) + (int)q;) i thought sum should be 5 but actually the output is 4. I tried line 12 in the interactions pane and indeed saw that sum=4. I don't get it. Shouldn't x++ yield 3 (x=2) and if this gets added to (int) q ( double q gave me sth like 2.666666), i should be getting 5. Can someone explain to me what happened?
Additionally,after getting my first output, how should I proceed?
The next condition is:
if (x > 5)
p += 4 / 2;
else
p += 3 % 1;
since x<5, i should go for the else condition, right?
My last question is that, after using p += 3%1, my p still remains 1, so do i return back to this loop (since p<12) or do I get out of this loop and proceed to line19? I'm not sure what to do.
In line 12 you are using post increment (x++). You should use pre increment ++x.
Post increment puts the current value of x in your statement, then increases x.
Pre increment initially increases x and after that puts result into your statement.
At your first time, 3%1=0
p +=3%1 => p+=0 thats why p still remains 1

Categories

Resources