No if-else branch is entered on certain values - java

I am have a little trouble with this java homework. I am still fairly new to this programming work. I am having trouble making the program do the following: Scientists measure an object’s mass in kilograms and its weight in Newtons. If you know the amount of mass that an object has, you can calculate its weight, in Newtons, with the following formula:
Weight = mass X 9.8
Write a program that asks the user to enter an object’s mass, and then calculate its weight. If the object weighs more than 1000 Newtons, display a message indicating that it is too heavy. If the object weighs less than 10 Newtons, display a message indicating that the object is too light.
this is what I have written so far:
import java.util.Scanner;
public class MassandWeight{
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
double mass;
System.out.print("Please enter the object's mass: ");
mass = keyboard.nextDouble();
// Convert the mass to weight using the following expression:
double weight = (mass * 9.8);
if (weight >= 10 && weight <= 1000)
System.out.println("The weight of the object is " + weight + ".");
else if (weight > 1001)
System.out.println("The object's weight is too heavy.");
else if (weight < 9)
System.out.println("The object's weight is too light.");
}
}
so everything works great! and I am really proud of myself for getting this far. however when I enter "1" i get no response back. everything else works great. if you need more information, please let me know. Thank you!!

You're checking for values of weight in (-∞, 9), [10, 1000] and (1001, +∞). This means that you're missing values in [9 and 10) and (1000, 1001]. If you input 1, the weight will be 9.8 and you'll be missing it.
Here's what your ifs should look like, instead:
if (weight >=10 && weight <= 1000) ...
else if (weight > 1000) ...
else if (weight < 10) ...

Since it's for a homework, I won't give it all out... but check your if/else... maybe put an else at the end so you can see the scenarios that are not caught with your else if.

When you enter 1 then the weight = (1* 9.8) = 9.8
you have 3 conditions:
1- weight >=10 && weight <= 1000
2- weight > 1001
3- weight < 9
so 9.8 doesn't match with this conditions
you need else {} at the end

Check the last else statement. It does not check if it is less than 10. When the weight is > 9 && < 10, no statement is executed (entering 1 sets the weight to 9.8)

I write else-if statements like this in ways that guarantee an execution of a path. Consider the following:
if (weight < 10) {
// too light
} else if (weight > 1000) {
// too heavy
} else {
// just right - this MUST be the case if
// the previous branches are not selected
}
Using an approach like this helps me reduce programming bugs and increase refactorability by removing duplication of comparissions. I also find it easier to read.
See TDWTF: But...Anything Can Happen! for an extreme perversion of duplicating comparisons: the posted code isn't nearly as bad, but in my opinion it suffers from the same fundamental flaw.

You have to change
else if (weight < 9)
to
else if (weight < 10)
and
else if (weight > 1001)
to
else if (weight > 1000)

Related

Is there a code on java that allows for two if statements with one independent statement for Shipping Charges?

I am very new to java and have been stuck on a program that I've been trying to create. For background knowledge purposes, the program is for a company called "Ship It" which is a package shipping company. The user enters the weight of the package, and the distance it will travel. Depending on the weight, the company charges a fee per 200 miles.
0 < weight <= 3 pounds $1.00 charge
3 < weight <= 6 pounds $2.00 charge
6 < weight <= 10 pounds $3.00 charge
10 < weight <= 20 pounds $4.00 charge
20 < weight <= 30 pounds $5.00 charge
So far, this is the code I have:
public static void main(String[] args)
{
Scanner kb = new Scanner (System.in);
//Variables
double costWithoutCharge = 0, weight, distance = 0;
//Introduction to ShipIt
System.out.print("\t\t******Welcome to ShipIt******\n");
System.out.print("***We are a low-charge, secure shipping company for packages" +
"up to 30 pounds***");
//User Enters Weight of Package
System.out.print("\n\nEnter the weight of the package (1.0 - 30.0 pounds): ");
weight = kb.nextDouble();
System.out.print("");
// User Enters distance the package will travel
System.out.print("Enter the miles to the destination (1 - 2000 miles): ");
distance = kb.nextInt();
System.out.print("");
//Weight If-else Statement
if (weight >30.0)
System.out.println ("\nSorry, you have entered invalid data - program terminated");
if (weight >30.0)
System.exit((int) weight);
//Distance Restriction if-else
if (distance >2000)
System.out.println ("\nSorry, you have entered invalid data - program terminated");
if (distance >2000)
System.exit((int) distance);
costWithoutCharge = distance / 200;
//If else
if (weight <0 || weight <=3)
{
System.out.println ("The cost to ship the package is: "+ "$" + (costWithoutCharge)*1.00);
}
else if (weight <3 || weight <= 6)
{
System.out.println ("The cost to ship the package is: "+ "$" + (costWithoutCharge)*2.00);
}
else if (weight <6 || weight <= 10)
{
System.out.println ("The cost to ship the package is: "+ "$" + (costWithoutCharge)*3.00);
}
else if (weight <10 || weight <= 20)
{
System.out.println ("The cost to ship the package is: "+ "$" + (costWithoutCharge)*4.00);
}
else {
System.out.println ("The cost to ship the package is: "+ "$" + (costWithoutCharge)*5.00);
}
kb.close();
}
}
As of now, if I put a value like 1001, the cost to ship is $15.015, but it should be $18 since the charge is multiplied per 200 miles. I am on the fence if I need to do a new equation for the charge per 200 miles dilemma or if it can be supported with another if-statement?
I feel as though I have tried everything but I can't seem to solve this ): I am in dire need of help! Please!
The weight is missing from your example.
it sounds like in your example you have:
distance 1001
weight between 6 and 10, resulting in a $3 charge per "beginning 200 miles"
From your code, 15.015 gets returned.
It appears you want to calculate the "beginning 200 miles", so you could achieve that by rounding up:
costWithoutCharge = Math.ceil( distance / 200 );
On another note, you may want to remove the common parts from your if/then/else block. That is, only perform the calculation but not the System.out.println inside each clause.
First
if (weight <0 || weight <=3)
should be
if (0 < weight && weight <=3)
However the code should be easier to maintain, use a table of limits:
double[][] weightsAndCharges = {
{3, 1.00},
{6, 2.00},
{10, 3.00},
{20, 4.00},
{30, 5.00}
};
double charge = 10.00;
for (double[] weightAndCharge : weightAndCharges) {
if (weight <= weightAndCharge[0]) {
charge = weightAndCharge[1];
break;
}
}
System.out.printf("The cost to ship the package is: $%0.2f%n", charge*distanceRatio);
The answer is some basic math.
What you are thinking of is a combinatorial explosion: If you layer a whole batch of if/elseif statements inside each of your weight if statements for e.g. if (miles < 200) ... else if (miles >= 200 && miles < 400) - then think of it in dimensions: You have the 'miles' dimension which currently is adding 10 options (1-200, 200-399, 400-599, etc), the weight dimension which adds 5.
The amount of ifs you'd need here is then A*B: 50 ifs.
That's a ton, and clearly not what you want.
Math to the rescue!
You really just want to calculate costPerSegment * segments.
Calculate those 2 values individually, and now it's just A + B: 15 ifs. Given that you can actually use math itself to turn the miles number into the # of segments you need to charge (it's just division by 200 for the miles part, no lookup table involved), we're down to 5 ifs.
Note also your code is buggy. Your weight if statement have their > and < reversed. But the else if hides the problem. I fixed that problem in the snippet below.
double costPerSegment;
if (weight <=3) {
costPerSegment = 1.0;
} else if (weight <= 6) {
costPerSegment = 2.0;
} else if (weight <= 10) {
costPerSegment = 3.0;
} else if (weight <= 20) {
costPerSegment = 4.0;
} else {
costPerSegment = 5.0;
}
// Casting a positive double to an int automatically rounds down.
int segments = (int) miles / 200;
double cost = costPerSegment * segments;
This line is causing the problem for input distance 1001
costWithoutCharge = distance / 200; // result = 5,005
As far as I understood you want to have here just 5
So the simpliest solution would be to declare costWithoutCharge as int
and than
costWithoutCharge = (int) distance / 200; // result = 5
Or if you want to keep costWithoutCharge as double you can use Math lib to round it
costWithoutCharge = Math.round(distance / 200); // result = 5

Number Search (Most efficient)

Given that N is a random number (range 1 to 1000). We need to guess the N and for each guess, one of the following feedbacks may be given:
The guess is correct;
The guess is too large, so you should guess a smaller number;
The guess is too small, so you should guess a larger number.
In case 3, the value of N will increase by P, where P is another random number(range 1 to 200).
If the initial value of N=800 and P=150. You guess in the following sequence:
Example
How do you code the following especially when it involves two number (N and P). I was thinking of using Binary Search but the it would be a problem if we do not know the value of P.
This is my code as of now :
myGuess=0;
checkCode=0;
int lower = 1, upper = 999;
myGuess = (lower+upper)/2;
do{
if (checkCode == 2) {
upper = myGuess - 1;
}
else if (checkCode == 3){
lower = myGuess + 1;
upper += ran.nextInt(200); //Need to guess the P value
}
myGuess = (lower+upper)/2;
}while(checkCode!=1);
The first step is to obtain a working guessing system. This code provides a rough guide to a binary search approach. The second step would the be to analyze how to improve efficiency. (note: can restore some of the S.O.P() to see progress)
private static int doGuess()
{
int lowerBound = 1;
int upperBound = 1000;
int numberToGuess = ThreadLocalRandom.current().nextInt(upperBound) + 1;
int guess = 0;
int steps = 0;
int increases = 0;
while (guess != numberToGuess) {
++steps;
guess = (lowerBound + upperBound) / 2;
// System.out.printf("[%5d] Guessing %d (is: %d)%n",
// steps,
// guess,
// numberToGuess);
if (guess == numberToGuess) {
System.out.printf("Guessed %d in %d steps (%d increases)%n",
numberToGuess,
steps,
increases);
continue;
}
else if (guess > numberToGuess) {
// System.out.println("Guess is too high!");
// adjust upper bound to be guess
upperBound = guess;
}
else {
// System.out.println("Guess is too low; changing number");
numberToGuess += ThreadLocalRandom.current().nextInt(200) + 1;
// adjust lower bound to this guess
lowerBound = guess;
// the number moved, so adjust upper bound by max range
upperBound += 200;
// track increases
++increases;
}
}
return steps;
}
public static void main(String[] args)
{
List<Integer> steps = new ArrayList<>();
int iterations = 10;
for (int i = 0; i < iterations; ++i) {
steps.add(doGuess());
}
IntSummaryStatistics stats =
steps.stream().collect(IntSummaryStatistics::new,
IntSummaryStatistics::accept,
IntSummaryStatistics::combine);
System.out.println(stats);
}
Output:
Guessed 8838 in 145 steps (83 increases)
Guessed 6301 in 106 steps (59 increases)
Guessed 3239 in 58 steps (30 increases)
Guessed 5785 in 109 steps (58 increases)
Guessed 2547 in 56 steps (27 increases)
Guessed 16071 in 300 steps (164 increases)
Guessed 3847 in 54 steps (31 increases)
Guessed 3125 in 42 steps (24 increases)
Guessed 6708 in 93 steps (57 increases)
Guessed 7433 in 143 steps (74 increases)
IntSummaryStatistics{count=10, sum=1106, min=42, average=110.600000, max=300}
[Note: based upon quick simulations, the average across multiple runs is about 115, so efficiency improvements should reduce on average from 115 steps]
[Note: the amount of change in the code is different with each guess that is too low; a comment by the OP might suggest the increase is randomly chosen once, in which case the increase in the number to guess in the above code would need to change]
Edit:
Logically if guessing low moves the the number one is to guess, then using some sort of bias towards picking higher would seem to be logical. As Holger has suggest in the various comments, there are some ways to make adjustments.
I had attempted some basic adjustments prior to seeing Holger's suggestion; I then also attempted to implement his algorithm. However, I have not found the adjustments to make a marked improvement (and some are worse).
Using 100,000 runs, the standard binary search averaged 127.7 steps (note: up slightly from my earlier estimate based upon a lower run count). Assuming I implemented Holger's algorithm correctly, at 100,000 the average was 126.6 steps.
As I lack the math skills (and unfortunately time at the moment) to investigate further, it seems that simple modifications do not seem to radically change the efficiency of the algorithm on average. I did not investigate worse cases. It would be interesting to ask the question over on the Math StackExchange to see if they could provide any definite input. I did do a quick Google search, but did not have time to read the academic papers that might give some improvement (again, with unknown trade-offs in speed and algorithmic complexity).
It is, of course, possible I did not implement Holgen's suggestion properly. Here is the code I used (replacing the change in the guess calculation if too low) based straight from the comment:
if (tryHolgen) {
double risc = 200.0/(upperBound-lowerBound);
if (risc <= 1) {
guess = (upperBound + lowerBound) /2;
}
else {
guess = upperBound -
Math.max((int)((upperBound - lowerBound)/risc/2),1);
}
else {
guess = (lowerBound + upperBound) / 2;
}
I am curious if others have a better implementation than the straight binary search.
It is interesting, though, that a 1..1000 range with a standard binary search would take 8 steps on average with O(log n) complexity. By allowing the guess to change, it moves the average by about 120 steps.
I reworked my solution once I understood what you were trying to do. This will give you some statistics. The current solution incorporates a random number between 0 and 13 for each guess, as well as adding the lower and upper bound together and divide them by 2. Why 13? It seems like it's a sweet spot for this exact task.
public static void main(String args[]) throws IOException {
int numTests = 1000000;
long averageTries = 0;
int maxAttempts = 0;
int minAttempts = Integer.MAX_VALUE;
for (int i = 0; i < numTests; i++) {
int numAttempts = 0;
int answer = (int) (Math.random() * 1000) + 1;
int lower = 1;
int upper = 1000;
int myGuess;
do {
myGuess = (int) (((lower + upper) / 2) + (Math.random() * 14));
numAttempts++;
if (myGuess > answer) {
upper = myGuess;
} else if (myGuess < answer) {
lower = myGuess;
upper += (lower + upper) / 2;
answer += (int) (Math.random() * 200) + 1;
}
} while (myGuess != answer);
averageTries += numAttempts;
if (numAttempts > maxAttempts) {
maxAttempts = numAttempts;
}
if (numAttempts < minAttempts) {
minAttempts = numAttempts;
}
}
System.out.println("Average attempts (of " + numTests + " tests): " + (averageTries / numTests));
System.out.println("Most attempts in one run: " + maxAttempts);
System.out.println("Least attempts in one run: " + minAttempts);
}
Output:
Average attempts (of 1000000 tests): 266
Most attempts in one run: 72228
Least attempts in one run: 1
You can try to do something similar to binary search. Just consider that binary search requires the input to be sorted. If the input is not sorted you have to sort it yourself.
Rather than guessing a random number, just guess the one exactly in the middle of the partition. However compared with binary search which halves each time, in this case it's a moving target, so the bounds of the search need to be adjusted for that.

Calculating change in a program - Floating point error

I've been working on making a program to calculate change and the program never ends up running and terminating after completion. I don't know what's wrong with my code. If anyone could help that'd be great.
private static void calculateChange(double price, double given) {
int ones = 0, quarters = 0, dimes = 0, nickels = 0, pennies = 0;
double change = given - price;
while (change != 0) {
if (change >= 1) {
change = change - 1;
ones++;
}
if (change >= .25) {
change = change - 0.25;
quarters++;
}
if (change >= .10) {
change = change - .10;
dimes++;
}
if (change >= .05) {
change = change - .05;
nickels++;
}
if (change >= .01) {
change = change - .01;
pennies++;
}
}
System.out.println();
System.out.println("Correct Change");
System.out.println("Ones " + ones);
System.out.println("Quarters " + quarters);
System.out.println("Dimes " + dimes);
System.out.println("Nickels " + nickels);
System.out.println("Pennies " + pennies);
}
The double type is floating point, and floating point numbers trade precision for performance. At some point, when you are subtracting cents from change, it becomes less than 0.01 but greater than zero, or it becomes less than zero.
In either of these cases, all of your if conditionals will be false, but the while conditional still holds true, resulting in an infinite loop.
A quick solution would be to change your while condition from change != 0 to change >= 0.01.
A better solution would be to use an integral number type (such as int) and have it store the number of cents (so a dollar would be 100). This approach will not have any floating-point number inaccuracies.
Numbers like 0.1, 0.05 or 0.01 cannot be represented exactly as binary floating point numbers. Therefore your change probably never becomes zero.
Aside from using integers or BCD, you could allow a tolerance when checking for zero, for example
while (Math.abs(change) < 0.000001) {
...
}
Perhaps this is a floating point issue. Your double precision "change" will never excactly equal integer zero, thus your "while" test will always evauate true. Try doing something along the lines of
while(change >= epsilon)
Also... try using an if else-if chain...

How do I format the logic for 3 conditions and use a previous condition as well?

NOT ASKING FOR ANYONE TO WRITE THE PROGRAM FOR ME
I am having trouble understanding how to setup the logic for a program given these following conditions:
For every day late up to and including 7 days, the late fee is $0.10/day
After 7 days, for every day late up to and including 90 days, the late fee is $0.20/day.
(Example: a book returned 10 days late incurs a late fee of $1.30 late fee, $0.10 for each of the first 7 days plus $0.20 for each of the remaining 3 days)
This is where I am having issues. I am not sure how to include the previous condition along with this one. My best guess is some sort of nested loop or an elseif containing this condition and something about the last one?
After 90 days, an unreturned book is considered lost. All late fees are waived, but the borrower is charged the cost of the book, plus a $10 restocking fee.
This is my best attempt, but I'm not sure this is the most efficient logic:
if (daysLate > 90)
{
costDue = bookPrice + 10;
}
else if (daysLate <= 90)
{
costDue = (7*0.10) * (daysLate*0.20);
}
else if (daysLate <= 7)
{
costDue = daysLate*0.10;
}
else
{
IO.reportBadInput();
}
The second condition should be changed, otherwise the third if won't be reached. Also the third condition should be changed to check if the daysLate variable is greater or equal to zero:
if (daysLate > 90)
{
costDue = bookPrice + 10;
}
else if (daysLate >= 7)
{
costDue = (7*0.10) + ((daysLate - 7) * 0.20); // change here
}
else if (daysLate >= 0)
{
costDue = daysLate*0.10;
}
else
{
IO.reportBadInput();
}
if (daysLate > 90)
{
costDue = bookPrice + 10;
}
else if (daysLate > 7 && daysLate <= 90)
{
costDue = (7*0.10) * (daysLate*0.20);
}
else
{
costDue = daysLate*0.10;
}
Simply update the second clause and drop that last one, that'll straighten it out.
addition to all previous answers - the calculation for mid-term (between 7 days and 90) should have an addition instead of multiplication (7*0.10) + (daysLate*0.20); or even 1.30 + (daysLate*0.20); (as the problem description suggests)
When you use an if statement you have to make sure that it separates the cases that you want to keep separate. In your code, the first else if statement includes all instances where daysLate <= 90, so the second else if would never execute.
Also check your past 7 days due computation, its seems like you would be overcharging people for those first 7 days.
if (daysLate > 90)
{
costDue = bookPrice + 10;
}
else if (daysLate >= 0)
{
costDue = daysLate * 0.10;
if (daysLate > 7) {
costDue += (daysLate - 7) * 0.10;
}
} else {
IO.reportBadInput();
}
Another way to do this, while sacrificing readability a bit, and eliminating one else-if condition:
if (daysLate > 90) {
costDue = bookPrice + 10;
}
else if (daysLate >= 0 && daysLate <= 90) {
costDue = Math.min(7, daysLate) * 0.10 + Math.max(daysLate - 7, 0) * 0.20;
}
else {
IO.reportBadInput();
}

Creating Mulitple If statment for Converting height

public String convertHeightToFeetInches()
{
int leftOver = heightInInches % IN_PER_FOOT;
if(heightInInches < (IN_PER_FOOT * 2)){
return "1 foot " + leftOver + " inches";
}
else{ return "";
}
if(heightInInches < (IN_PER_FOOT * 3) && heightInInches > (heightInInches * 2)){
return "2 foot " + leftOver + " inches";
}
else{
return "";
}
I want to make it return "1 foot 4 inches" or however tall they are..
I got the first if statment to work but what would i do to continue up to like 6 feet.. I tried just adding another one but im pretty sure thats not how to do it. How can i put this together?
Wouldn't it be simpler just to calculate the foot as well?
public String convertHeightToFeetInches()
{
int inches = heightInInches % IN_PER_FOOT;
int foot = heightInInches / IN_PER_FOOT;
return "" + foot + " foot and " + inches + " inches";
}
It's possible to use a division statement to come up with the number if feet in 'heightInInches'.
Can you try that?
For example, I'm confident that if I know someone is 50 inches tall, I can quickly calculate that the person is at least 4 feet tall.
Once you have that working, we'll work on the inches.
You have most of the logic correct as it is, but you do need a little push. Consider a height between 1 and 2 feet. In mathematical terms, we would describe this as 1 < x <= 2. Consider now what that would translate to in Java - what about x must be true? Hint: it's two conditions.
Next, an if-else if-else won't work if you have an else just sitting there. else will execute if nothing else matches with it (and that will occur often). Place an if after those elses.

Categories