I am a beginner programmer learning Java. I am doing an exercise where the user enters the number of minutes, and I print out the number of years and days.
I have put together some if statements to print out the amount of years & days, or days only depending on the amount of minutes the user entered.
The if statements fail to work (the first statement gets executed) if the variable year is a double. As soon as I narrow it to an (int) it works fine. I tested it with 2880 minutes, so the value for year should be clearly less than one, and the second if else statement should be executed.
Any help on why this is happening would be appreciated (I am aware that doubles are not totally accurate, but my test case should work as the value for years should be way below 1). Thanks!
import java.util.Scanner;
public class NumberOfYears {
public static void main(String[] args) {
//Set up Scanner object
Scanner input = new Scanner(System.in);
//Get the number of minutes from the user
System.out.print("Enter the number of minutes: ");
int minutes = input.nextInt();
//Determine the amount days / years
double days = minutes / 60.0 / 24;
double years = days / 365.0;
//Print out results
if ( years > 0) {
System.out.println(minutes + " minutes is approximately " + (int) years + " years and " + (int) days % 365
+ " days.");
} else if ( days > 0) {
System.out.println(minutes + " minutes is approximately " + (int) days + " days.");
} else {
System.out.println(minutes + " minutes is less than one day.");
}
}
}
In your if statement, you wrote if (years > 0). Should be if (years > 1). Same with your if (days > 0). Simple as that. There is nothing wrong with floating point math in java or your usage.
I get the following:
Enter the number of minutes: 2880
2880 minutes is approximately 0.005479452054794521 years and 2 days.
code seems to work fine when casting years as a double
I would say the correct approach is to have int types for days and years as well. Then, use integer division (described here) to calculate the number of days and years. There is no reason to have day and year double variables.
Related
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
I'm trying to make a program that takes an input amount and separates them into how many coins it would equal. So far what i wrote gives me the right amount most of the time but sometimes it will be a penny off and i don't know why.
public static void main(String[] args) {
double amount;
System.out.println("This program will display the number of "
+ "quarters, dimes, nickels and pennies based on the "
+ "amount you enter below.");
System.out.println();
System.out.print("Please enter an amount: ");
Scanner scan = new Scanner(System.in);
amount = scan.nextDouble();
double quarter = amount/0.25;
amount = amount % 0.25;
double dime = amount/0.10;
amount = amount % 0.10;
double nickel = amount/0.05;
amount = amount % 0.05;
double penny = amount/0.01;
System.out.println("Quarters: " + (int)quarter);
System.out.println("Dimes " + (int)dime);
System.out.println("Nickels " + (int)nickel);
System.out.println("Pennies " + (int)penny);
When i input 2.47, i get:
Please enter an amount: 2.47
Quarters: 9
Dimes: 2
Nickels: 0
Pennies: 2
But when i input 1.47, i get:
Please enter an amount: 1.47
Quarters: 5
Dimes: 2
Nickels: 0
Pennies: 1
The most likely reason for your problem is that floating point arithmetic is subject to rounding errors. At a certain point, one of the intermediate floating point results is not completely accurate, and the error is amplified when you use a cast to convert the double to an int.
For a full explanation of why this sort of thing happens, read the answers to Is floating point math broken?
Solution You should recode this using the int (or long) type to represent a whole number of cents.
Start with this:
long amount = (long) (100 * scan.nextDouble());
and then recode the rest of the method accordingly.
This is an exercise question taken from Java Software Solutions: foundations of program design by Lewis & Loftus, 4th edition ; Question PP2.6 (here is a link)
Question is as follows: " Create a project that reads a value representing a number of seconds, then print the equivalent amount of time as a combination of
hours, minutes, and seconds. (For example, 9999 seconds is equivalent
to 2 hours, 46 minutes, and 39 seconds.)"
I have so far tried the following
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
double totalSecs, seconds, minutes, hours;
System.out.println("Enter number of seconds: ");
totalSecs = scan.nextInt();
hours = totalSecs/3600;
minutes = (Math.abs(Math.round(hours)-hours))*60;
seconds = (Math.abs(Math.round(minutes)-minutes))*60;
System.out.print(hours + "\n" + minutes + "\n" + seconds);
}
Answer came out to,
hours: 2.7775
minutes: 13.350000000000009
seconds: 21.00000000000051
What I want to do is take the decimals of, say, hours and multiply them by 60 to get minutes and repeat the process for seconds. I'm however having trouble figuring it out, hence the messy solution of (Math.abs) etc.
What would you recommend me to change/add? Thanks!
Note: This is a book for beginners, hence I've not learned many more operations than those I've already stated in the code. As such, I haven't understood the solution for the previous times this question has been asked.
As an alternative of user2004685's answer;
int seconds = 9999;
int hour = 9999 / (60 * 60); //int variables holds only integer so hour will be 2
seconds = 9999 % (60 * 60); // use modulo to take seconds without hours so it will be 2799
int minute = seconds / 60; //same as int variable so minute will be 49
seconds = seconds % 60; // modulo again to take only seconds
System.out.println(hour + ":" + minute + ":" + seconds);
Here is a much simpler way of doing it:
public static void main (String[] args) throws Exception {
SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss");
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
System.out.println(sf.format(new Date(9999000)));
}
Note: Please note that this will only show the output in 24-hour format and if number of hours is greater than 24 then it'll increment a day and will start over. For example, 30 hours will be displayed as 06:xx:xx. Also, you'll have to pass the input in milliseconds instead of seconds.
If you want to do it your way then you should probably do something like this:
public static void main (String[] args) throws Exception {
long input = 9999;
long hours = (input - input%3600)/3600;
long minutes = (input%3600 - input%3600%60)/60;
long seconds = input%3600%60;
System.out.println("Hours: " + hours + " Minutes: " + minutes + " Seconds: " + seconds);
}
Output:
Hours: 2 Minutes: 46 Seconds: 39
I've been trying to convert a float number to years, months, weeks, days, hours, minutes and seconds but I'm not getting it.
For example, if the user enters 768.96 the total would be 2 years, 1 month, 1 week, 1 day, 23 hours, 0 minutes and 2 seconds.
This is what I have.
import javax.swing.JOptionPane;
public class timePartition {
public static void main(String[] args) {
float totalTime;
float userInput;
int years = 0, months = 0, weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0;
do{
userInput = Float.parseFloat(JOptionPane.showInputDialog("Enter a positive number to decompose"));
totalTime = userInput;
years = (int) userInput / 365;
userInput = userInput % 10;
months = (int) userInput / 12;
userInput = userInput % 10;
weeks = (int) userInput / 4;
userInput = userInput % 10;
days = (int) userInput / 30;
userInput = userInput % 10;
hours = (int) userInput / 24;
userInput = userInput % 10;
minutes = (int) userInput / 60;
userInput = userInput % 10;
seconds = (int) userInput / 60;
userInput = userInput % 10;
}while (userInput >=1);
System.out.print("The number " +totalTime+ " is " +years+ " years, " +months+ " months, " +weeks+ " weeks, " +days+ " days, " +hours+ " hours, " +minutes+ " minutes, " +seconds+ " seconds.");
}
I don't think you can use modulo 10 to reduce the input after you pull out each of the denominations. Also, you don't need a while loop at all for this.
You have to do something like
years = (int) (userInput / 365);
userInput = userInput - years*365;
and so on. Also, since the input is in days, you have to keep thinking in days when you divide out, so dividing by 12 to get the number of months doesn't make sense. You would instead divide by 30, 31 or 28. Similarly for hours, you would have to multiply the remaining fraction of days by 24, and then take the fractional part of the hours and decompose it similarly into minutes and seconds.
Ok, several things here:
just to make sure you're aware: date/time arithmetic is not as simple as it may seem. Several fields are not uniform in duration, including years (due to leap years in some years but not others), months (28-31 days depending on the month), and even minutes (due to rare but strictly necessary leap seconds). This means that technically you can't properly decompose a total duration count (e.g. "x days") into duration fields, and vice-versa (at least not without some "anchoring" date/time point).
if you want to make incorrect assumptions like "all years have exactly 365 days" and "all months have exactly 30 days" and "all minutes have exactly 60 seconds" then this can be done.
I'm not sure whether you wanted your program to take and decompose a single value, in which case the loop is not necessary, or multiple values, in which case the final print statement should be inside the loop. I've assumed the latter.
based on your example input and the start of your decomposition code, it appears that you want the integral part of the input float value to represent a number of days, with the fractional part representing a time value as a fraction of one day. Your decomposition code is incorrect according to this interpretation; you first must separate the ipart and fpart to decompose independently, and in each step of the decomposition, you must take the remainder on the previous field duration size (e.g. 7 days for a week, 3600 seconds for an hour), rather than a fixed value of 10 (not sure where that came from...) to prepare for the next step of the decomposition. This can be done with the mod-assign operator %=.
Here's working code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class TimePartition {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.println("Enter a positive number to decompose");
String input = br.readLine();
if (input.equals("")) break;
float inputAsFloat = Float.parseFloat(input);
if (inputAsFloat == 0.0) break;
// the input is an integral day count, with a possible fractional part representing time as a fraction of one day
int totalDays = (int)inputAsFloat;
int totalSeconds = (int)((inputAsFloat-totalDays)*60.0*60.0*24.0);
// decompose totalDays into date fields
int years = 0;
int months = 0;
int weeks = 0;
int days = 0;
// ignores leap years
years = (int)totalDays/365;
totalDays %= 365;
// assumes all months have 30 days
months = (int)totalDays/30;
totalDays %= 30;
weeks = (int)totalDays/7;
totalDays %= 7;
days = (int)totalDays;
// decompose totalSeconds into time fields
int hours = 0;
int minutes = 0;
int seconds = 0;
hours = (int)totalSeconds/3600;
totalSeconds %= 3600;
// ignores leap seconds
minutes = (int)totalSeconds/60;
totalSeconds %= 60;
seconds = (int)totalSeconds;
System.out.println("The number "+inputAsFloat+" is "+years+" years, "+months+" months, "+weeks+" weeks, "+days+" days, "+hours+" hours, "+minutes+" minutes, "+seconds+" seconds.");
} // end while
} // end main()
} // end class TimePartition
Demo:
bash> ls
TimePartition.java
bash> javac TimePartition.java
bash> ls
TimePartition.class* TimePartition.java
bash> CLASSPATH=. java TimePartition
Enter a positive number to decompose
768.96
The number 768.96 is 2 years, 1 months, 1 weeks, 1 days, 23 hours, 2 minutes, 25 seconds.
I suppose the input is in day.
There are few strange thing in your code :
the while loop is not necessary
(int) userInput will cast userInput in int before the division, not really important here, but be careful ;)
userInput % 10 everywhere
divide by 12 to get the number of month, by 4 to get the number of weeks, and so on
Here is a skeleton of the solution:
float userInput /* = ... */ ;
int years = (int)(userInput/365) ;
userInput = userInput - years*365 ; // or userInput%365 ;
int month = (int)(userInput/30);
userInput = userInput - month*30 ; // or userInput%30 ;
int day = (int) userInput ;
userInput = userInput - day ;
userInput = userInput * 24 ; //transform in hours
int hours = (int)hours ;
userInput = userInput - hours ;
userInput = userInput * 60 ; // transform in minute
int minutes = (int)userInput ;
userInput = userInput - minutes ;
userInput = userInput * 60 ; // transform in second
int seconds = (int) userInput ;
Basically, there is a group of 20 sheep. After the group has grown to a population of 80 sheep, the group does not need to be supervised anymore. The number of sheep, N, each year, t, is found with :
N = 220/(1 + 10(0.83)^t)
This program tries to find out how many years the sheep have to be supervised and writes out the value of N for t starting at zero and going up to 25.
This is my code so far...it doesn't seem to work and I know there is something to do with the part about multiplying with the power. I'm trying to use a variable "power" that is multiplied by 0.83 in each iteration of the loop. Any help is appreciated, thank you.
public static void main(String[] args) {
System.out.println("A breeding group of 20 bighorn sheep is released in a protected area in Colorado.");
System.out.println("After the group has reached a size of 80 sheep, the group does not need to be supervised anymore.");
System.out.println("This program calculates how many years the sheep have to be supervised.");
int number = 20;
int power = 1;
for(int years = 0; number < 80; power*= 0.83) {
number = 220 / (1 + 10 * power);
System.out.println("After " + years + " years, the number of sheep is: " + number);
years++;
}
}
}
change your data types on number and power from int to double. I tried it and it runs correctly. You also might want to modify your for loop to run while years < 25 rather than number < 80. And make number a local variable inside the loop for cleanliness.
public static void main(String[] args) {
System.out.println("A breeding group of 20 bighorn sheep is released in a protected area in Colorado.");
System.out.println("After the group has reached a size of 80 sheep, the group does not need to be supervised anymore.");
System.out.println("This program calculates how many years the sheep have to be supervised.");
double power = 1;
boolean foundFirstOverEighty = false;
for (int years = 0; years < 25; years++) {
double number = 220 / (1 + 10 * power);
System.out.println("After " + years + " years, the number of sheep is: " + number);
if (!foundFirstOverEighty && number >= 80) {
System.out.println("First time number of sheep exceeded eighty. " + years + " years. number of sheep is: " + number);
foundFirstOverEighty = true;
}
power *= 0.83;
}
}
I have to make this GUI that is a CD calculator.
I put in the Initial investment ($): e.g. 2000
the Annual interest rate (%): e.g. (8%)
Ending value ($): e.g. 5000
The program then outputs on a jLabel: The amount of years required are "12" (e.g.)
I need to make a do while loop and a counter.
I did the get text from the 3 text fields then add the initialInvestment with the annual rate % but having trouble with the loop and the counter?
int initialInvestment, endValue, cdvalue;
double cdValue, annualDecimalConvert, annualRate;
initialInvestment = Integer.parseInt(initialInvestmentInput.getText());
annualRate = Double.parseDouble(interestRateInput.getText())/100;
endValue = Integer.parseInt(endingValueInput.getText());
cdValue = initialInvestment + (initialInvestment * annualRate);
double a = cdValue;
while (a <= endValue){
a = a++;
yearsOutput.setText("The required year needed is: " + a);
}
You're simply adding 1 to a every iteration of the loop. So it'll take a few thousand iterations that way to fullfil the loop requirements.
What you have to do is keep adding the interest every year while keeping count of the years and only update the output after you're done looping.
int initialInvestment, endValue;
double cdValue, annualDecimalConvert, annualRate;
initialInvestment = Integer.parseInt(initialInvestmentInput.getText());
annualRate = Double.parseDouble(interestRateInput.getText())/100;
endValue = Integer.parseInt(endingValueInput.getText());
// First year interest is counted here.
cdValue = initialInvestment + (initialInvestment * annualRate);
int years = 1;
while (cdValue < endValue){
cdValue = cdValue + (cdValue * annualRate);
years++;
}
yearsOutput.setText("The required year needed is: " + years);