Formatting Numbers to Army Time (Big Java Ex. 4.15) - java

I just started learning Java last week and am currently stuck on my exercise. Basically the problem is you take two numbers in army time, and then output what the difference is For example
Please Enter First time : 0900
Please Enter second time: 1730
Result - > 8 hours and 30 minutes
The bonus of the problem is to make sure the program works if the first time is bigger than the second. First I'm trying to solve the first part and heres what I have so far
class TimeInterval{
private double timeOne;
private double timeTwo;
public TimeInterval(double timeOne, double timeTwo){
timeOne = this.timeOne;
timeTwo = this.timeTwo;
}
public double getMinutes(){
double minuteDiff = timeTwo - timeOne;
minuteDiff = minuteDiff%60.0;
return minuteDiff;
}
public double getHours(){
double hours = timeTwo - timeOne;
hours = hours - getMinutes();
hours = hours/60.0;
return hours;
}
}
public class DataSet{
public static void main(String [] args){
TimeInterval time = new TimeInterval(0900,1730);
}
}
Now heres whats trippy. I'd like to make my new object with timeOne as 0900, but I'm getting an error. It says "Integer too long", that seems pretty funny to me so I did some research. In the last section of my book in chapter 4 we talking about formatting stuff, like with System.out.printf, and like %d, %f
I looked on SO and I found a way where I can do something like
String.format("%05d", yournumber);
Here you can put 5 0's before your number. The thing is, I'm not really sure how to implement this into my code. I tried setting timeTwo = String.format... etc, but then since its a string I can't really do math on it. Also it won't let me convert it to a double after String.format. How should I do approach my issue?

Numeric literals that start with a zero are interpreted as octal numbers, base 8, which can only use digits 0-7.
Thus the numeric literal 0900 is an invalid octal number. Try:
TimeInterval time = new TimeInterval(900, 1730);
Tip: Avoid using double for you fields and parameters. Use int instead, which will not suffer the imprecision of double. int can handle any number/time you need.

Related

How do i convert a double into an int when converting minutes to seconds in java

Trying to convert minutes to seconds with the starting data being a double,
so for example 33.51 seconds (33 mins 51 seconds)
How to convert that to an int when converting to seconeds only
My code for now would accept it if there was no double point to begin with, so i only used ints only
and it seems to work, but when i have that double in there it doesnt, is therre a better approach to it .
Heres my code for now
public class Runner {
//fields setting up the variables
String MembershipID;
String name;
int time ;
//constructor1 filling in the details
public Runner(String Mem, String na, int ti) {
MembershipID = Mem;
name = na; //This
time = ti;
}
public String getMembershipID() {
return MembershipID;
}
public String getName() {
return name;
} //setting it up for the main method from the constructor fields above
public int getTime() {
int mins = time *60;
return mins;
}
public static void main(String[] args) { //initializing the membership name and time,
Runner a = new Runner("RF23", "George Formsby", 33); //Creating a new instance of
Runner, filling out the details from the sample data provided.
Runner b = new Runner("RG89", "Neil Innes", 32);
Runner c = new Runner("ST200", "Sandy Denny", 30); // With mem and na being
represented from my constructor
System.out.println("MembershipID is: " + a.getMembershipID());
System.out.println("Name is: " + a.getName());
System.out.println("Time in seconds: " + a.getTime());
System.out.println("MembershipID is: " + b.getMembershipID());
System.out.println("Name is: " + b.getName());
System.out.println("Time is: " + b.getTime());
System.out.println("MembershipID is: " + c.getMembershipID());
System.out.println("Name is: " + c.getName());
System.out.println("Time is: " + c.getTime());
}
}
Seems like simple enough math.
Convert minutes + seconds to just seconds
int minutes = ...;
int seconds = ...;
int totalSeconds = minutes * 60 + seconds;
Convert minutes (as a double) to seconds
double time = 12.33;
int seconds = (int) (0.5 + time * 60);
Explanation: when rounding to an int, java lops off the decimal parts. We want to round to the nearest second, which can be trivially accomplished (for positive numbers!) by adding 0.5 to it and then casting to int.
NB: See note below!
Convert seconds (as int) to minutes (as double)
int totalSeconds = ....;
double time = time / 60.0;
Explanation: In java, The syntactic construct x / y is considered to be 'integer division' if x and y are both integral data types (byte, short, int, long, or char). It is considered 'floating point division' if either x or y is a floating point type (float or double). integer division will lop off the decimal digits (so, it rounds down for positive results, and rounds up for negative results). Thus, 90 / 2, for example, resolves to 1. Not 1.5. On the other hand, 90 / 2.0 resolves to 1.5, because at least one of the two numbers is a double (2.0 is a double constant, 2 is an int constant). Hence why we divide by 60.0 and not 60.
NB: Important thing to think about: PRECISION.
Computers aren't magical, and double is precisely defined as consisting of exactly 64 bits.
You can't store one of an infinite sequence of options in a finite storage space, so, computers cannot store numbers perfectly. A 64-bit storage space has the ability to give you at most 2^64 different 'options'. If the storage space is storing a number, that means there are at most 2^64 numbers it could possibly store there, and all other numbers therefore simply cannot be represented by it. Somebody needs to go out and define which numbers are 'blessed' - capable of being stored. Then someone needs to define what happens if you attempt to store a non-blessed number in them.
For the integer data types, this is easy: int (32-bit) can store 2^32 numbers. Which numbers are blessed? Simply -2^31 to +2^31 -1. When you attempt to store something above or below it, the numbers just loop around:
int reallyLarge = Integer.MAX_VALUE; // this is 2^31-1.
int surelyThisIsEvenLarger = reallyLarge + 1;
Actually, surelyThisIsEvenLarger is negative number instead. It looped around.
For double and float it is way more complicated. Even between just 0 and 1 there are infinite numbers! The blessed numbers are chosen by more or less throwing darts at the numberline, focusing about half the darts close to 1.0, with fewer and fewer darts hitting the number line as you move away from 1.0. Eventually, at around 2^52, the 'distance' between any 2 darts is higher than 1.0, even.
It's a bit like how we humans do it: We cannot 'represent' 1 divided by 3, at all. 0.333333.... it never ends.
To make matters worse, computers count in binary and not decimal. So, where we humans can e.g. do '1 divided by 10' (that's 0.1, so it is a blessed number in the system of 'a human writes it down in decimal on a bit of paper that has room for about 10 digits'), computers cannot do that, either.
Thus, most of the 'take these number of seconds and turn them into a double' values, are not actually blessed, so it is important to realize what happens when you try to make a double that isn't blessed: The computer will round it off to the closest blessed number. You can't ask for the error (the amount it rounded by), or ask it not to do this; not with double, anyway.
If you do enough back-and-forth math on them, those errors compound and eventually will be flat out wrong. That's one of the many reasons why you should most definitely never, ever use double to store money values. For race monitoring you're running into a similar situation here, best not to use them. Better to pick an atomic unit and store in those. For example, why not store in millis? The current record for fastest mile is 3:43.13. In 'millis', that becomes long fastestMile = 223130; - no need to involve those nasty doubles with their bizarro rounding behaviours.

java removing trailing decimal digits causing .0 become .99

I want to simply have a function that converts a double with as many decimal places into 4 decimal places without rounding.
I have this code that has been working fine but found a random instance where it turned .0 into .99
Here are some sample outputs
4.12897456 ->4.1289
4.5 ->4.5
4.5231->4.5231
5.53->5.53
5.52->5.199 (Wrong conversion, I want it to be 5.52)
private static double get4Donly(double val){
double converted = ((long)(val * 1e4)) / 1e4;
return converted
}
EDIT: This conversion is called thousands of times, so please suggest a method where I dont have to create a new string all the time.
You can use DecimalFormat
import java.text.DecimalFormat;
import java.math.RoundingMode;
import java.util.Arrays;
public class MyClass {
public static void main(String args[]) {
DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.DOWN);
for (Number n : Arrays.asList(4.12897456, 4.5, 4.5231, 5.53, 5.52)) {
Double d = n.doubleValue();
System.out.println(df.format(d));
}
}
}
RoundingMode.DOWN rounds towards zero, new DecimalFormat("#.####") creates a DecimalFormat instance that formats numbers to a maximum of 4 decimal places. Put those two together and the above code produces the following output, which I believe matches your expectations:
4.1289
4.5
4.5231
5.53
5.52
Doubles just don't work like you think they do.
They are stored in a binary form, not a decimal form. Just like '1 divided by 3' is not representable in a decimal double (0.3333333333 is not enough, it's infinite 3s, so not representable, so you get a rounding error), but '1 divided by 5' is representable just fine, there are numbers that are representable, and numbers that end up rounded when storing things in a double type, but crucially things that seem perfectly roundable in decimal may not be roundable in binary.
Given that they don't match up, your idea of 'eh, I will multiply by 4, turn it to a long, then convert back to a double, then divide by 1000' is not going to let those digits go through unmolested. This is not how you round things, as you're introducing additional loss in addition to the loss you already started out with due to using doubles.
You have 3 solutions available:
Just print it properly
A double cannot be considered to 'have 4 digits after the decimal separator' because a double isn't decimal.
Therefore, it doesn't even make sense to say: Please round this double to at most 4 fractional digits.
That is the crucial realisation. Once you understand that you'll be well along the way :)
What you CAN do is 'please take this double and print it by using no more than 4 digits after the decimal separator'.
String out = String.format("%.4f", 5.52);
or you can use System.printf(XXX) which is short for System.print(String.format(XXX)).
This is probably what you want
forget doubles entirely
For some domains its better to ditch doubles and switch to longs or ints. For example, if you're doing finances, it's better to store the atomic unit as per that currency in a long, and forego doubles instead. So, for dollars, store cents-in-a-long. For euros, the same. For bitcoin, store satoshis. Write custom rendering to render back in a form that is palatable for that currency:
long value = 450; // $4.50
String formatCurrency(long cents) {
return String.format("%s%s%d.%02d", cents < 0 ? "-" : " ", "$", Math.abs(cents) / 100, Math.abs(cents) % 100);
}
Use BigDecimal
This is generally more trouble than it is worth, but it stores every digit, decimally - it represent everything decimal notation can (and it also cannot represent anything else - 1 divided by 3 is impossible in BigDecimal).
I would recommend using the .substring() method by converting the double to a String. It is much easier to understand and achieve since you do not require the number to be rounded.
Moreover, it is the most simple out of all the other methods, such as using DecimalFormat
In that case, you could do it like so:
private static double get4Donly(double val){
String num = String.valueOf(val);
return Double.parseDouble(num.substring(0, 6));
}
However, if the length of the result is smaller than 6 characters, you can do:
private static double get4Donly(double val){
String num = String.valueOf(val);
if(num.length()>6) {
return Double.parseDouble(num.substring(0, 6));
}else {
return val;
}
}

CURRENCY - Round double value ONLY if it has more than 2 decimal places [duplicate]

This question already has answers here:
Why not use Double or Float to represent currency?
(16 answers)
Closed 3 years ago.
I'm trying to split a bill and need to calculate how much each person would owe if the bill was split in even amounts. I know one amount will be different than the rest to account for the lost cents.
Assume 3 people try to split a bill for 200. 200 / 3 is 66.6666666667. What I planned on doing was charging the 2 first people 66.67 and the last gets lucky with the 66.66 bill.
At the minute, I have this so far:
private String calculateAmountToPay(String noOfParticipants, String owed) {
double amountOwed = Double.parseDouble(owed);
int noOfMembers = Integer.parseInt(noOfParticipants);
DecimalFormat amountFormat = new DecimalFormat("#.##");
amountFormat.setRoundingMode(RoundingMode.CEILING);
return amountFormat.format((amountOwed/(double)noOfMembers) / 100);
}
But this always will return 66.67. Is there a way that I can get it to only round up if there is a number greater than 2 decimal places, if not, it stays at 66.66 for example?
Maybe I'm approaching this the wrong way. I know currency can be finicky to deal with.
Before even thinking about arithmetic, you need to know that double is not an appropriate data type for use with currency, because it’s imprecise. So, stop using a floating point type (eg double) as the data type for the quantity of dollars and start using a precise type (eg long) as the data type for the quantity of cents.
The steps then to do the calculation would be to immediately convert everything, with rounding, to cents:
double amountOwed = ...;
int noOfMembers = ...;
long centsOwed = Math.round(amountOwed * 100);
long portionCents = Math.round(amountOwed * 100 / noOfMembers);
long errorCents = portionCents * noOfMembers - centsOwed;
Here’s one way to deal with the error:
long lastPortionCents = portionCents - errorCents;
But it’s possible that the error is more than 1 cent, so a better solution would be to spread the error out evenly by subtracting (or adding if the error is negative) 1 cent from the first (or last, or randomly chosen) errorCents diners.
The rest of the solution is then about rending the above, which I leave to the reader.
As a side note, using cents is how banks transmit amounts (at least for EFTPOS anyway).
Regarding basic software design, I would create a separate method that accepts integer cents and people count as its parameters and returns an array of the "split" amounts. Doing this will not only make your code easier to read, but it will compartmentaise the arithmetic operation and thus enable lots of simple tests to more easily be written, so you can know you have all the edge cases that you can think of covered.
You can use BigDecimal with half rounding mode:
private String calculateAmountToPay(String noOfParticipants, String owed) {
double amountOwed = Double.parseDouble(owed);
int noOfMembers = Integer.parseInt(noOfParticipants);
BigDecimal amount= new BigDecimal((amountOwed / (double) noOfMembers) / 100);
return amount.setScale(2, RoundingMode.HALF_UP).toString();
}
You can just do all the computation with basic primitives converting everything to cents (2 decimals precision), and dividing the left over cents over a portion of the members, no need to overcomplicate it with extra sdks/math manipulations. The following is a working example solving this problem entirely, using these suggestions:
public class AmountDivider {
private int totalMembers, luckies, unluckies;
private double totalAmount, amountPerLucky, amountPerUnlucky;
public AmountDivider(int numMembers, double amountOwed) {
totalMembers = numMembers;
totalAmount = amountOwed;
double centsOwed = amountOwed * 100;
int centsPerMember = (int)(centsOwed / totalMembers);
int centsLeft = (int)centsOwed - centsPerMember * totalMembers;
luckies = totalMembers - centsLeft;
amountPerLucky = centsPerMember / 100.0;
unluckies = centsLeft;
amountPerUnlucky = (centsPerMember + 1) / 100.0;
}
public String toString() {
String luckiesStr = String.format("%d lucky persons will pay %.2f", luckies, amountPerLucky);
String unluckiesStr = String.format("%d unlucky persons will pay %.2f", unluckies, amountPerUnlucky);
return String.format("For amount %f divided among %d: \n%s\n%s\n",
totalAmount, totalMembers, luckiesStr, unluckiesStr);
}
public static void main(String[] args) {
System.out.println(new AmountDivider(3, 200));
System.out.println(new AmountDivider(17, 365.99));
}
}
Complete code on GitHub
Hope this helps.

How to always round in two decimals

For a project at school, I have to make a java program to retrieve data from a database.
This is my code:
import java.text.*;
import java.util.*;
public class Tijdstip
{
public Tijdstip()
{
}
public double testTijd(String tijdstip1)
{
// splitting the time
String[] tokens = tijdstip1.split("\\s+");
int hours = Integer.parseInt(tokens[0]);
int minutes = Integer.parseInt(tokens[1]);
//returning the time
double result = hours + ((double)minutes/100);
return result;
}
}
I fill in a time as string like: "7 10", meaning 7:10am and it must return a double like 7.10
But it returns 7.1, how do I make it so it will return 7.10 instead of 7.1?
You need to understand the difference between how a number is represented and how it is displayed. There is no numeric difference between 7.1 and 7.10; there is no way to make the number one instead of the other. You can display 7.1 as 7.10 using output formatting such as found in the Format class.
As a side issue: Storing this as a double would be a bad idea in a program of any size. There are many classes for representing time, and they all take into account the non-decimal nature of time divisions. Doubles don't do this.
Try this
new DecimalFormat("#.00").format(result);
The short answer is that you cannot do this if you must keep the result as a double. The double doesn't know anything about leading or trailing zeros. You can only do this when the result is formatted as a String. E.g., String.format("%.2f", 7.1) gives the string "7.10". You can easily do this formatting every time you display the number, but you cannot make the number itself remember the extra zero.
When you return double it will always truncate your last number if it is zero. so make it a string and return
If you need double value which has only two digits after dicimal, you can try following:
double d = 1.164444;
double r = Math.rint(d * 100)/100;
System.out.println(r);

How to round an answer to a mathematical equation

All-
I have an app in which the users inputs data such as the cost of a dinner bill and the tip percentage and the number of people. The app than takes the numbers and outputs the total bill cost and the amount each person has to pay. I am almost there but when the user inputs numbers that don't work well I get outputs like $23.576 or $34.999999999. My question is how do I make the app round the two output answers to two decimal places ($55.349 goes to $55.35)?
Thanks in advance!
String roundTwoDecimals(double d) {
DecimalFormat formatter = new DecimalFormat("#.##");
return formatter.format(d);
}
You can use Math.round like so:
double data = 55.349; // Your data value of whatever
int decimalPlaces = 2;
double roundBase = Math.pow(10, decimalPlaces);
data = (double)(Math.round(data * roundBase)) / roundBase;
System.out.println(data); // Prints "55.35"
Keep in mind, however: you should NOT use double when it comes to financial applications. Since yours appears to be small-scale, you should be fine, however, BigDecimal is much easier to use for purposes like these.
How to use BigDecimal: clicky.

Categories

Resources