BodyMassIndex calculator error (NaN) - java

I am getting a NaN error when I compile this, i can't figure out what I am doing wrong? I tried moving the variables around to see if I could get them working but nothing. Notice the variable I put of type double i used for bmi after inches = keyboard.nextInt(); I think its a divide by zero error but i dont know what i am dividing by zero.
import java.util.Scanner;
public class BodyMassIndex {
public static void main(String[] args) {
// TODO Auto-generated method stub
int pounds =0;
int feet = 0;
int inches = 0;
double heightMeters = ((feet * 12) + inches) * .0254;
double mass = pounds / 2.2;
Scanner keyboard = new Scanner(System.in);
System.out.println("Enter your weight in pounds");
pounds = keyboard.nextInt();
System.out.println("Enter how many feet you are");
feet = keyboard.nextInt();
System.out.println("Enter how many inches after feet");
inches = keyboard.nextInt();
double bmi = mass / (heightMeters * heightMeters);
System.out.println(mass);
System.out.println(bmi);
if(bmi < 18.5){
System.out.println("Underweight");
}
else if ((bmi >= 18.5) && (bmi < 25)){
System.out.println("Normal weight");
}
else if ((bmi >= 25) && (bmi < 30))
System.out.println("Above weight");
else
System.out.println("Obese");
}
}

It's important to understand the dynamic nature of your variables, such that when you type
double heightMeters = ((feet * 12) + inches) * .0254;
This assignment is immediately evaluated using the current values of feet and inches (which are 0 at that moment), before any of the keyboard entry is performed. To perform these calculations with the values entered by the keyboard, these calculations need to be performed and their results assigned to their corresponding variables after the keyboard entry is done, when the current values of pounds, feet and inches are what you just entered. Because heightMeters is still zero from its initialization and hasn't been changed since, you're getting a divide by zero.

You're getting the exception because the value of heightMeters is 0 here:
double bmi = mass / (heightMeters * heightMeters);
The only time that heightMeters is calculated, the result of it is 0:
double heightMeters = ((feet * 12) + inches) * .0254;
It looks like you want to use this calculation, so I'd split it into a separate function:
public static double getHeightInMeters(int feet, int inches)
{
return 0.0254 * ((feet * 12) + inches);
}
Then you can call it later:
double heightMeters = this.getHeightInMeters(feet, inches);
double bmi = mass / (heightMeters * heightMeters);

Related

Java BMI program

The first part of the code is working, the program takes inputs as height and weight as displays an output message. When I press n I can go to the second part and take inputs for height in inches and the weight in pounds. As soon as I take them the program outputs the resulting bmi is: Nan. and the variable bmi might not have been initialized. i want to convert the height and weight from inches and pounds to meters and then show the resulting bmi This is my code:
package uly14th;
import java.util.Scanner;
public class BmiCalculator {
private static float BMI2;
public static void main(String[] args) {
char Y;
char y;
char Q;
char n;
char N;
float heightInMeters, weightInKilograms, BMI;
float heightInInches, weightInpounds;
float heightInMeters2 = 0, weightInKilograms2 = 0;
Scanner input = new Scanner(System.in);
System.out.println("Please state whether you are going to use kilograms & meters or, inches & pounds");
System.out.println("If you want to use the former please press Y or if you want to use the latter please press N");
Q = input.next().charAt(0);
if(Q == 'y' || Q == 'Y' ) {
System.out.println("Please enter the height in meters: ");
heightInMeters = input.nextFloat();
System.out.println(" and weight in kilograms: ");
weightInKilograms = input.nextFloat();
BMI = weightInKilograms / (heightInMeters * heightInMeters);
System.out.println("The resulting BMI of the person is: " +BMI);
if (BMI < 18.5){
System.out.println("The personis underweight");
}
else if ((BMI<=25.0) && (BMI >= 18.5)){
System.out.println("The person is normal");
}
else if ((BMI >= 25.0) && (BMI <=30.0 )){
System.out.println("The personis obese");
}
else if(BMI>=30.0) {
System.out.println("The person is obese and should exercise");
}
}
if ((Q == 'n') || (Q == 'N')){
System.out.println("Please enter the height in inches: ");
heightInInches = input.nextFloat();
System.out.println("Please enter the weight in pounds: ");
weightInpounds = input.nextFloat();
heightInInches = 0.0254f * heightInMeters2;
weightInpounds = 0.453592f * weightInKilograms2;
BMI = weightInKilograms / (heightInMeters * heightInMeters);
System.out.println("The resulting BMI of the person is: " +BMI);
if (BMI < 18.5){
System.out.println("The personis underweight");
}
else if ((BMI<=25.0) && (BMI >= 18.5)){
System.out.println("The person is normal");
}
else if ((BMI >= 25.0) && (BMI <=30.0 )){
System.out.println("The personis obese");
}
else if(BMI>=30.0) {
System.out.println("The person is obese and should exercise");
}
}
else {
System.out.println("Please make sure you run the program again and then only use the characters n,N,y,Y. ");
}
}
}
This is the error message: Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - variable BMI might not have been initialized
at uly14th.BmiCalculator.main(BmiCalculator.java:82)
At the row (line 82)
BMI = weightInKilograms / (heightInMeters * heightInMeters);
you use the variables weightInKilograms and heightInMeters which has never been initialized, hence your error.
I suspect you want to do the conversion to meters and kilograms from inches and pounds before calculating the BMI. You can do this by simply putting the following lines before the BMI calculation
heightInMeters = 0.0254f * heightInInches;
weightInKilograms = 0.453592f * weightInPounds;
BMI = weightInKilograms / (heightInMeters * heightInMeters); //Now you can calculate the BMI using your variables since they have been assigned a value and is therefore initialized
heightInMeters = 0.0254f * heightInInches ;
weightInKilograms = 0.453592f * weightInpounds ;
BMI = weightInKilograms / (heightInMeters * heightInMeters);
should do the trick (... in case the constants are correct)

Computing BMI and How to Prevent Rounding Up Floating Points (Java)

I'm writing a program that will calculate the BMI of a person. Here's the assignment that I was given:
"Body Mass Index (BMI) is a measure of health on weight. It can be calculated by taking your weight in kilograms and dividing by the square of your height in meters. Write a program that prompts the user to enter a weight W in pounds and height H in inches and displays the BMI. Note that one pound is 0.45359237 kilograms and one inch is 0.0254 meters."
Input: (Line 1) Real number within 50 to 200
(Line 2) Real number within 10 to 100
Output: BMI value (Floating point should only be printed until the second decimal point)
The problem is that whenever I use "System.out.printf("%.2f\n", BMI)", the output is rounded up rather than cutting off the rest of the decimal point. Here's my code:
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
double weight = input.nextDouble();
double height = input.nextDouble();
double weightKG;
double heightM;
double heightMSquare;
double BMI;
final double kilogram = 0.45359237;
final double meter = 0.0254;
while ((weight > 200) || (weight < 50)) // Error catching code.
{
weight = input.nextDouble();
}
while ((height > 100) || (height < 10))
{
height = input.nextDouble();
}
weightKG = weight * kilogram; // Convert pounds and inches to
kilograms and meters.
heightM = height * meter;
heightMSquare = Math.pow(heightM, 2); // Compute square of height in
meters.
BMI = weightKG / heightMSquare; // Calculate BMI by dividing weight
by height.
System.out.printf("%.2f\n", BMI);
}
}
Here is a method I wrote that solves this with regexes and string manipulation.
private static String format2Dp(double x) {
String d = Double.toString(x);
Matcher m = Pattern.compile("\\.(\\d+)").matcher(d);
if (!m.find()) {
return d;
}
String decimalPart = m.group(1);
if (decimalPart.length() == 1) {
return d.replaceAll("\\.(\\d+)", "." + decimalPart + "0");
}
return d.replaceAll("\\.(\\d+)", "." + decimalPart.substring(0, 2));
}
What I did was turning the double to a string, extract the decimal part out of it and substringing the decimal part. If the decimal part is only 1 character long, add a zero to the end.
This method works with numbers expressed in scientific notation as well.

Return in the method overloading

I'm new to Java and I'm learning it myself. I met a trouble when I try the method overloading. This is the code
public static void main(String[] args) {
calculateScore();
calculateScore(500);
calculateScore("Duy", 600);
calcFeetAndInchesToCentimetres(100, 3.5);
calcFeetAndInchesToCentimetres(100*12 + 3.5);
}
public static double calcFeetAndInchesToCentimetres(double feet, double inches) {
if (feet >= 0 && inches >= 0 && inches <= 12) {
double footToInches = feet * 12;
double centimetres = (inches + footToInches) * 2.54;
System.out.println("The value in centimetres is " + centimetres + " cm.");
return centimetres;
} else {
return -1;
}
}
public static double calcFeetAndInchesToCentimetres(double inches) {
if (inches >= 0){
double inchesToFeet = inches / 12;
double inchesRemain = inches - (inchesToFeet * 12);
calcFeetAndInchesToCentimetres(inchesToFeet, inchesRemain);
return 0;
} else {
return -1;
}
My problem is when I take the return 0 from the second method, the debugger says "missing return statement". Then I tried to put return calcFeetAndInchesToCentimetres(inches);, it works but the program runs for about many thousands times.
Then I put return 0 and everything is OK. But I don't understand why I can't put the return calcFeetAndInchesToCentimetres(inches); and why do I need a return statement when the method above (with 2 parameters) had it alredy. And if I want to have the value of centimetres converted when I execute the second method (with "inches" parameter only) what do I have to do?
One other thing I've realized that in this blockcode
double inchesToFeet = inches / 12;
double inchesRemain = inches - (inchesToFeet * 12);
calcFeetAndInchesToCentimetres(inchesToFeet, inchesRemain);
the inchesRemain will be 0? But the method works very well. When I change inchesToFeet = inches % 12, it just not shows anything. Why?
It should just be:
public static double calcFeetAndInchesToCentimetres(double inches) {
if (inches >= 0){
double inchesToFeet = inches / 12;
double inchesRemain = inches - (inchesToFeet * 12);
return calcFeetAndInchesToCentimetres(inchesToFeet, inchesRemain);
} else {
return -1;
}
}
You said you've tried return calcFeetAndInchesToCentimetres(inches); but that's just calling your method recursively and it recurses forever as there is no stopping condition.
With method overloading, you have two different methods.
calcFeetAndInchesToCentimetres that takes a single argument
calcFeetAndInchesToCentimetres that takes two arguments
Now when you call calcFeetAndInchesToCentimetres(inches); you are calling the one that takes a single argument. If you call that from inside itself, it will continue calling itself infinite times. This is the error you are seeing.
If you replace that with return calcFeetAndInchesToCentimetres(inchesToFeet, inchesRemain); that will call the other method - the one that takes two arguments. That's what you actually want to do.
Fixed version:
public static double calcFeetAndInchesToCentimetres(double inches) {
if (inches >= 0){
double inchesToFeet = inches / 12;
double inchesRemain = inches - (inchesToFeet * 12);
return calcFeetAndInchesToCentimetres(inchesToFeet, inchesRemain);
} else {
return -1;
}
}
public static void main(String[] args) {
calculateScore();
calculateScore(500);
calculateScore("Duy", 600);
calcFeetAndInchesToCentimetres(100, 3.5);
calcFeetAndInchesToCentimetres(100*12 + 3.5);
}
public static double calcFeetAndInchesToCentimetres(double feet, double inches) {
if (feet >= 0 && inches >= 0 && inches <= 12) {
double footToInches = feet * 12;
double centimetres = (inches + footToInches) * 2.54;
System.out.println("The value in centimetres is " + centimetres + " cm.");
return centimetres;
} else {
return -1;
}
}
public static double calcFeetAndInchesToCentimetres(double inches) {
if (inches >= 0){
double inchesToFeet = inches / 12;
double inchesRemain = inches - (inchesToFeet * 12);
calcFeetAndInchesToCentimetres(inchesToFeet, inchesRemain);
return 0; //Here
} else {
return -1;
}
If you remove return 0 it is showing missing return statement because you are in a if-else loop.
Lets say your input inches is less than 0 then it will go the else part and return the -1.. but if the inches inputed are more than 0 then it will go to the if condition and when it will reach the end of the if statement then there would be nothing to return so for a if-else condition both if and else should return something.
Other way to go around this is make a local variable out of if-else condition and return if after the else part is done.. In this way weather it goes in if or else part of the code both times there would be some value for that local variable to be returned..
Now for second part of your question:
your code will look like
line 1 public static double calcFeetAndInchesToCentimetres(double inches) {
line 2 if (inches >= 0){
line 3 double inchesToFeet = inches / 12;
line 4 double inchesRemain = inches - (inchesToFeet * 12);
line 5 calcFeetAndInchesToCentimetres(inchesToFeet, inchesRemain);
line 6 return calcFeetAndInchesToCentimetres(inches);
} else {
return -1;
}
So in this case you are calling the same method itself again and again..
You start from line 1 go till line 6 then you call the same method and the execution starts again and line 1 will be executed till line 6 and again line 1 over and over again until all memory is lost and a stackoverflow occours..
Best practiced code can look like this:
public static double calcFeetAndInchesToCentimetres(double feet, double inches) {
double centimetres = 0.0;
if (feet >= 0 && inches >= 0 && inches <= 12) {
double footToInches = feet * 12;
centimetres = (inches + footToInches) * 2.54;
System.out.println("The value in centimetres is " + centimetres + " cm.");
} else {
centimetres = -1;
}
return centimetres;
}
public static double calcFeetAndInchesToCentimetres(double inches) {
double centimeters = 0;
if (inches >= 0) {
double inchesToFeet = inches / 12;
double inchesRemain = inches - (inchesToFeet * 12);
centimeters = calcFeetAndInchesToCentimetres(inchesToFeet, inchesRemain);
} else {
centimeters = -1;
}
return centimeters; //Here
}

Trying to Understand Where My Loop Goes Wrong

So here is my task:
A postal company for a package charges $15 for the first
pound or a fraction thereof and $10 per pound for anything over one
pound. Write a program that prints the charge of a package.
Variables:
weight
First execution:
Weight? -12 Weight must be a positive number.
Second Execution:
Weight? 0 Weight must be a positive number.
Third Execution:
Weight? 2 Pay: $25.00
Forth Execution:
Weight? 2.8 Pay: $33.00
Fifth Execution:
Weight? 2.07 Pay: $25.70
and Here is the code I have developed so far:
import java.text.DecimalFormat;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
double weight;
double cost = 15.00; // set first pound to $15
double output = 0;
System.out.print("Weight?: ");
weight = keyboard.nextDouble();
if (weight <= 0) {
System.out.println("Weight must be a positive number.");
} else if (weight == 1) {
// Print the charge of the package
output = output + cost;
DecimalFormat money = new DecimalFormat("$0.00");
System.out.println("Pay: " + money.format(output));
} else {
for (double i = 1; i < weight; i = i + .01) {
if (weight > 1) {
output = output + (1 / 10.00);
}
}
// Print the charge of the package
output = output + cost;
DecimalFormat money = new DecimalFormat("$0.00");
System.out.println("Pay: " + money.format(output));
}
}
}
Everything works, but what I can't figure out is why (especially in the Fourth and Fifth Execution) is the final output always .10 cents off. Can anyone help me get to the accuracy I need?
Here is what I came up with:
Scanner keyboard = new Scanner(System.in);
double weight;
double cost = 15.00; // set first pound to $15
double output = 0;
System.out.print("Weight?: ");
weight = keyboard.nextDouble();
if (weight <= 0) {
System.out.println("Weight must be a positive number.");
} else {
// Print the charge of the package
if (weight > 1) {
output = cost + ((weight-1) * 10);
} else {
output = cost;
}
DecimalFormat money = new DecimalFormat("$0.00");
System.out.println("Pay: " + money.format(output));
}
This should handle all of your cases, as well as numbers between 0 and 1 assuming it's $1 per 0.1 lbs. Instead of your for-loop, you can just use the cost + ((weight-1) * 10) formula. I removed the check to see if weight was equal to 1 because it's handled in the else clause.
If I understand the question correctly, you should never have any fractional dollar amount because anything over a pound is automatically rounded up to the next pound. ie: 2.01 lbs would become 3 lbs. If this is correct, then you could use Math's ceil function to round the weight up to the nearest whole pound, then do something like this:
public class Main {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
double weight;
double cost = 15.00; // set first pound to $15
double output = 0;
System.out.print("Weight?: ");
weight = keyboard.nextDouble();
if (weight <= 0) {
System.out.println("Weight must be a positive number.");
} else if (weight == 1) {
// Print the charge of the package
output = output + cost;
DecimalFormat money = new DecimalFormat("$0.00");
System.out.println("Pay: " + money.format(output));
} else {
double temp = (Math.ceil(weight)) - 1;
for(double i = temp; i > 0; i-- ) {
output += 10;
}
output += cost;
DecimalFormat money = new DecimalFormat("$0.00");
System.out.println("Pay: " + money.format(output));
}
}
}
This way, you don't need to bother with 10 cent increments. I hope this helps. Let me know if you have any questions.
This: double i = 1; i < weight; i = i + .01 could be your problem.
Doubles are not exact for decimal math. You're expecting i == weight, at which point the loop should stop, but it might not because i + .01 (however many times) is a tiny fraction less than weight.
My advice is to ditch the loop. If the package is over 1 lb, just subtract one pound from the weight, multiply by the $10 per pound, and then round to the two decimal places you need (NOTE: round it according to how it's spec'd to be rounded, don't just let the conversion from double to decimal do it on its own. There are multiple ways to round something, and decimal does not magically know which one is right for your problem.)
EDIT: Look at your solution, is it supposed to only work to a resolution of 1/10 of a lb? If so, start by rounding the weight. Again, round it according to how it needs to be rounded (down, up, or nearest).

Working out taxable income Java

I have just finished a Java test at university and I know that I have answered a particular question wrong and would just like some help / clarification please?
The question was as follows:
implement a method that takes someones income and works out the tax.
If that person earns less than 7500 then tax = 0.
If that person earns between 7501 and 45000 then tax = 20%, less the 7500, which is tax free.
Finally, if that person earns above 45001 then tax = 40%, less the income in the 20% bracket, and then less the 7500 which is tax free.
As time was running short, I just did a basic if else statement showing income and tax brackets, example below.
public static double incomeTax(double income){
if(income <= 7500){
income = income * 0;
}
else if(income >= 7501 && income <= 45000){
income = income * 0.8;
}
else(income >= 45001){
income = income * 0.6;
}
return income;
}
I know that the code is not correct, no where near, but as it was coming to the end of the test I gave it a go in a hope just to get a mark for the if else statements.
I would really appreciate any help here.
Thank you.
After great feedback, this is what I came back with (with a LOT of help!!:] )...
import java.util.Scanner;
public class TaxableIncome
{
public static void main(String[] args){
netIncome();
}
public static double netIncome() {
double income = 0;
Scanner in = new Scanner(System.in);
System.out.print("Enter income: ");
income = in.nextDouble();
System.out.println();
double tax1 = 0;
double tax2 = 0;
double totalTax = tax1 + tax2;
// high income bracket
if (income > 45000) {
double part1 = income - 45000; // part = income - 45000
tax1 += part1 * 0.4; // tax = tax + part * 0.4
System.out.println("High Tax Band - Greater than 45000: " + tax1);
}
// medium income bracket
if (income > 7500) {
double part2 = income - 7500;
tax2 += part2 * 0.2;
System.out.println("Medium Tax Band - Greater than 7500: " + tax2);
}
System.out.println("Total Tax = " + (tax1 + tax2));
// tax for low income is zero, we don't need to compute anything.
return totalTax;
}
}
A simple answer would be as this:
public static double netIncome(double income) {
double tax = 0;
// high income bracket
if (income > 45000) {
double part = income - 45000;
tax += part * 0.4;
income = 45000;
}
// medium income bracket
if (income > 7500) {
double part = income - 7500;
tax += part * 0.2;
}
// tax for low income is zero, we don't need to compute anything.
return tax;
}
This way you calculate the tax for each tax bracket and sum them.
I see nothing wrong with the logic. The main issue you had was you just need to return the income tax, not the total income. So the value you needed to return was income*whateverPercentTax.
Also, I would've tried:
if(income < 7001){
}else if(income >=45001){
}else{}
But that is just me.
I would start with something like this:
public static double incomeTax(int income) {
final double band00Income = (double) Math.min(income, 7500);
final double band20Income = (double) Math.min(income - band00Income, 45000 - 7500);
final double band40Income = (double) Math.max(income - 45000, 0);
final double tax = band20Income * 0.2 + band40Income * 0.4;
return tax;
}
Note that income is an int due to a peculiarity of the tax calculation in the UK - it also solves the problem with the unspecified cases between 7500.01 and 7500.99 inclusive.
A better solution would extract constants for all the magic numbers. An even better solution would generalise the bands and rates into a table so that they can be changed easily.
A complete answer might include test cases like this:
import org.junit.Assert;
import org.junit.Test;
public class TestTax
{
public static final double DELTA = 0.1;
#Test
public void testTax() {
Assert.assertEquals(0.0, incomeTax(-3000), DELTA);
Assert.assertEquals(0.0, incomeTax(0), DELTA);
Assert.assertEquals(0.2, incomeTax(7501), DELTA);
Assert.assertEquals(3000.0, incomeTax(22500), DELTA);
Assert.assertEquals(7500.0, incomeTax(45000), DELTA);
Assert.assertEquals(7500.4, incomeTax(45001), DELTA);
Assert.assertEquals(25500.0, incomeTax(90000), DELTA);
}
public static double incomeTax(int income) {
final double band00Income = (double) Math.min(income, 7500);
final double band20Income = (double) Math.min(income - band00Income, 45000 - 7500);
final double band40Income = (double) Math.max(income - 45000, 0);
final double tax = band20Income * 0.2 + band40Income * 0.4;
return tax;
}
}
You'd have to tax things in bands. Dirty (untested) code:
public static double incomeTax(double income){
double tax = 0;
if(income > 7500){
tax += Math.min(45000-7500, income-7500)*.2;
}
if(income > 45000){
tax += (income-45000)*.4;
}
return tax;
}
You need to attempt to apply the tax rates more than once. Your code only hits one tax bracket. If I made 100k, I would have been taxed at 40% for the whole 100k. Here is something I came up with quickly.
public static double incomeTax(double income)
{
double tax = 0.0;
int midLevel = 7500;
int highLevel = 45000;
if (income <= 7500)
{
// Could early exit at this point and return already set tax
tax = 0.0;
}
if (income > midLevel)
{
// Find range of income > 7500, less than 4500. 37499 max
double taxableIncome = Math.min(income - midLevel, highLevel - midLevel - 1);
tax += taxableIncome * 0.2;
}
if (income > highLevel)
{
// Income above 45k
double taxableIncome = income - highLevel;
tax += taxableIncome * 0.4;
}
return tax;
}
You could try this, just copy your income brackets in the bracket array. Make sure you have infinity in bracket array and start with 0 in rate array.
import java.util.Scanner;
import java.text.DecimalFormat;
class IncomeTaxWithBrackets {
public static void main(String[] args) {
double infinity = Double.POSITIVE_INFINITY;
double [] bracket = {0, 7565, 25903, 54987, 121121, 567894, infinity};
double [] rate = {0, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35};
// bracket[0] to bracket[1] are assigned rate[1]
double income = 0;
double tax = 0;
System.out.print("\nPlease enter your income: ");
Scanner keyboard = new Scanner (System.in);
DecimalFormat dollar = new DecimalFormat ("$#,##0.00");
income = keyboard.nextDouble();
int x,i;
for (i=0; i <= 5; i++) {
if (income > bracket[i] && income <= bracket[i+1]) {
for (x=0; x<i; ++x) {
tax = tax + (bracket[x+1] - bracket[x]) * rate[x+1];
}
tax = tax + (income - bracket[i]) * rate[i+1];
}
}
System.out.println("\nWith a taxable income of "+dollar.format(income)+", your personal income tax is "+dollar.format(tax));
}
}
Let me know what you think.

Categories

Resources