How do I use "BigDecimal" in Java for my specific code? - java

I'm very new to programming in Java. I have been given an assignment in my school to solve the following exercise:
"Create two variables, each containing a number. Put out a message that shows how often the second number fits into the first one, and the rest (if there is one)" [I hope the wording is clear. I'm translating this from my native language german into english]
Now in general, I have solved the exercise like this (using Netbeans):
double numberOne = 10, numberTwo = 35.55;
double result, rest;
String conversion, numberOutput;
result = numberTwo / numberOne;
conversion = Double.toString(result);
int indexOfComma = conversion.indexOf(".");
numberOutput = conversion.substring(0, indexOfComma);
rest = numberTwo % numberOne;
System.out.println("The second number fits " + numberOutput +
" times into the first one. The rest is: " + rest);
With the numbers provided, the system pops out this message:
"The second number fits 3 times into the first one. The rest is: 5.549999999999997"
I don't like the rounding error for the rest. I expected it to give out "5.55" like a human would type or write it. After a bit of googling around it seems that something called "BigDecimal" is the solution to my problem, but the explanations I found of how to implement this in Java go wayyy over my head.
Would you be so kind as to show me exactly where and how I need to use BigDecimal in the above code to get the desired output? I would also be happy to see any alternative solutions you can think of.

BigDecimal version of your code:
BigDecimal numberOne = new BigDecimal("10");
BigDecimal numberTwo = new BigDecimal("35.55");
BigDecimal[] divRem = numberTwo.divideAndRemainder(numberOne);
System.out.println("The second number fits " + divRem[0].stripTrailingZeros().toPlainString() +
" times into the first one. The rest is: " + divRem[1].stripTrailingZeros().toPlainString());
Output
The second number fits 3 times into the first one. The rest is: 5.55

You can use BigDecimal like
BigDecimal a = BigDecimal.valueOf(10);
BigDecimal b = BigDecimal.valueOf(35.55);
BigDecimal c = b.divide(a, 3, BigDecimal.HALF_UP);
System.out.println(b + " / " + a + " = " + c);
Or you could use rounding like
System.out.printf("(int)(%.2f / %d) = %d%n", 35.55, 10, (int) (35.55 / 10));
System.out.printf("%.2f %% %d = %.2f%n", 35.55, 10, 35.55 % 10);
which prints
floor(35.55 / 10) = 3
35.55 % 10 = 5.55

Related

StreamTokenizer input number and parsed number are different

I have a StreamTokenizer that accepts numbers. However, the parsed number is not the same as the input.
Sample code:
String str = "1000000000000.0000000000000";
double initial = 1000000000000.0000000000000;
InputStream in = new ByteArrayInputStream(str.getBytes());
StreamTokenizer input = new StreamTokenizer(new BufferedReader(new InputStreamReader(in)));
input.parseNumbers();
int n = input.nextToken();
if (n == StreamTokenizer.TT_NUMBER) {
System.out.println("Original: " + str);
System.out.println("Parsed: " + input.nval);
System.out.println(initial + " == " + input.nval + " -> " + (initial == input.nval));
}
Output:
Original: 1000000000000.0000000000000
Parsed: 9.999999999999999E11
1.0E12 == 9.999999999999999E11 -> false
How can this be prevented so the two double values are equal?
EDIT: Linked question discusses why this issue appears. I am asking what are the possible ways to avoid this issue.
An exact way of representing numbers is usage of BigDecimal. Double has a certain precision and working with doubles of various precision (EX: double1=10000.0 and double2=0.0001) could result that the 0.0001 to be dropped. BigDecimal avoids that.
The disadvantages of BigDecimal:
it's slower
operators +, -, *, and / are not overloaded
But if you are dealing with money or having precision is a must, you should use BigDecimal, otherwise you will have losses.
EX:
String str = "1.0E12";
double initial = 1000000000000.0000000000000;
BigDecimal exVal = new BigDecimal(str);
System.out.println("Original: " + str);
System.out.println("Parsed: " + exVal);
System.out.println(initial + " == " + exVal + " -> " + (initial == exVal.doubleValue()));
Program output:
Original: 1.0E12
Parsed: 1.0E+12
1.0E12 == 1.0E+12 -> true
As per David Conrad's analysis, the StreamTokenizer classes handling of numbers with decimal points is flawed, and there doesn't appear to be a work-around.
But this is only one of many short-comings flaws in this class. You would be better off using Scanner or String.split. If the input is really complicated, consider using a parser generator to generate a lexer / parser that precisely implements your input syntax.
Related bugs:
JDK-4638205 : StreamTokenizer: lost precision when parsing long values
JDK-4146533 : java.io.StreamTokenizer: Want to parse scientific numbers
JDK-8180207 : deprecate StringTokenizer and StreamTokenizer
Having said that, applications that use floating point numbers should be tolerant of issues caused by rounding errors and imprecision. There are a number of Q&As on the best way to compare floating point numbers; e.g.
Manipulating and comparing floating points in java

How to round a large decimal value in Java?

I'm trying in the following code to round a decimal number based on the decimal format that I set at the beginning:
DecimalFormat df = new DecimalFormat("#.000");
df.setRoundingMode(RoundingMode.FLOOR);
double a = Double.parseDouble(df.format(43.473684210526315));
double b = Math.pow(a, 10);
double c = Double.parseDouble(df.format(b));
System.out.println(a + " ** " + b + " ** " + c);
The result that I got is:
43.473 ** 2.4109939006965688E16 ** 2.4109939006965688E16
As you see, the value of a is formatted properly. While the other values are not. After spending a long time trying to understand what is going on, I found out the value 2.4109939006965688E16 can not be formatted. I tested the same value after removing E16 and it worked.
My question is how can I round such a large decimal so that it works as the a?
It's pure luck that a works. If the initial value was 43.4701 you would be seeing 43.47. And in some cases you would see more than 3 decimal places due to the inaccuracy of double.
You only use the DecimalFormatter to create a String briefly before turning back into a double again. You want to keep and use that string.
DecimalFormat df = new DecimalFormat("#.000");
double b = Math.pow(43.473684210526315, 10);
String bFormatted = df.format(b);
System.out.println(bFormatted);
Gives you your desired output 24115485538109308.000
For your "big" decimals you can use the following format:
DecimalFormat df2 = new DecimalFormat("#.000E0");
I see several issues here:
You do not specify a locale for your DecimalFormat. So the combination of DecimalFormat.format and Double.parseDouble is error prone, as e.g. with german locale, DecimalFormat.format will use a comma as decimal separator, which is unsupported by Double.parseDouble, and will throw a NumberFormatException. You should use both format and parse of your DecimalFormat.
Also, you use your double values directly for System.out.println. Why not concatenating the results of DecimalFormat.format, to achieve exactly what you want? E.g. System.out.println(df.format(a) + " ** " + df.format(b) + " ** " + df.format(c));
If you want to do real mathematical rounding (e.g. needing the double value for additional calculations), use Math.round. You can multiply and divide by 10, 100, 1000 etc. to achieve the desired precision. Note that, with the double data type, you can't do exact rounding.
For large numbers, you'll need to use BigInteger or BigDecimal
DecimalFormat df = new DecimalFormat("#.000");
df.setRoundingMode(RoundingMode.FLOOR);
BigDecimal a = new BigDecimal(43.473);
BigDecimal b = a.pow(10);
System.out.println(df.format(a) + " ** " + b.doubleValue() + " ** " + df.format(b));
This results in the following output
43.472 ** 2.4109939006965688E16 ** 24109939006965686.655

Converting user input from binary to decimal using Modulus Operator in Java

I am having a hard time figuring out the answer to a homework assignment for Programming 1 class. The assignment is prompt a user for input (up to 4 bits) in binary, and convert it to the decimal equivalent. Using loops, conditional statements, ParseInt, and anything other than the modulus operator and other math operators are not allowed.
I am having trouble with the mathematical aspect, I think once I understand how to use the modulus operator to answer the question I would be able to write the code for it.
I have searched and have not been able to find anything that was able to help.
You should be getting the number values of each position and add them using the power of 2 to get back the original number.
double num = 1110;
double ones = Math.floor(num % 10);
double tens = Math.floor(num/10 % 10);
double hundreds = Math.floor(num/100 % 10);
double thousands = Math.floor(num %10000 /1000);
double tenThousands = Math.floor(num / 10000 % 10);
double original = (ones * 1) +
(tens * 2) +
(hundreds * 4) +
(thousands * 8);
System.out.println(num);
System.out.println("ones: " +ones);
System.out.println("tens: " +tens);
System.out.println("hundreds: " +hundreds);
System.out.println("thousands: " + thousands);
System.out.println("original number : " + original);

how to exchange an amount of money into notes and coins

how can I exchange a given amount of money into notes and coins? lets say input is 1234,26
and we have notes for 1000, 500, 200, 100, 50, and coins for 20, 10, 1, and 0.5? so if input is greater than .25 and less than .75 it should be rounded to 1x 0.5 if its between .75 and 1.00 it should be rounded to 1x 1 and if its less than .25 it should be rounded to nothing?ยจ
for this exact program the desired output would look something like this:
1x: 1000
1x: 200
1x: 20
1x: 10
4x: 1
1x: 0.5
if it wasnt for the 0.5 coin, I think I would have been able to do it using int and %, but as of right now I am pretty much clueless(think I have to use array, but im not sure how) and have no idea how to start. also im beginnner, if you can keep that in mind as well when answering and explaining! any tips/solutions? thanks in advance!
like this?:
System.out.println((input/1000) + " thousand " + ((input/500)%2) + " fivehundred " + (input/200%2.5) + " two hundred " + (input/100%2) + " hundred " + (input/50%2) + " fifty " + (input/20%2.5) + " twenty " + (input/10%2) + " ten " + input/1%10 + " one " );
still not sure how to deal with the 0.5 since I have to use int, input only cuz if I use double I get it completely wrong, I also have to use a if statement for the 0.5 coin..
I believe this is the standard approach to this kind of question.
double input = 1234.26;
int thousands = input/1000;
input = input - 1000*thousands; //So now it would 234,26
int fivehundreds = input/500;
input = input - 500*fivehundreds;
etc...
Right, but you can't convert from double to int (i.e. thousands is an int, but input is a double, so input/1000 is a double). So you have a few options:
Make thousands, fivehundreds, etc... be double. That is kinda ugly, though, there's no way they will have any decimal valu
Casting mean anything to you? For example, (int)int thousands = input/1000; will work. You can read up on "casting", but basically I'm just telling Java to treat that number as an int, not a double
Keep input as a int, and round it down. Then just check at the end if it has a decimal value (input % 1 > 0), and if it does, you need a half dollar.

Why is it adding the variables wrong?

I'm using Java but, it's not adding the amount correctly. I'll give my parts of my code.
final double taxrate=.08;
Map<String,Integer> Priceproduct= new HashMap<String,Integer>();
Priceproduct.put("shoes",(int) 50.00);
Priceproduct.put("shirts",(int) 30.00);
Priceproduct.put("shorts",(int) 75.00);
Priceproduct.put("caps",(int) 15.00);
Priceproduct.put("jackets",(int) 100.00);
System.out.print("\n Enter the product: ");
String product=keyboard.nextLine();
System.out.print( "\n Enter the quantity of the product");
int quantity=keyboard.nextInt();
int cost= Priceproduct.get(product)*quantity;
int tax= (int) (cost*taxrate);
System.out.print("\n tax=" +cost*taxrate+"");
int TotalBill= cost+tax;
System.out.print("\nTotal="+cost+ + +tax+"");
When it adds the cost and tax (those two are correct) it's gets the completely wrong answer.
For example 3 shirts= 90, the tax equals 7.2, and the total becomes 907.
Do I need to use DecimalFormat or something else?
Change this:
System.out.print("\nTotal="+cost+ + +tax+"");
to this:
System.out.println();
System.out.print("Total=" + (cost + tax));
(The problem is that + is left-associative, so without parentheses around your addition, "a" + b + c means ("a" + b) + c, which does string-concatenation at both stages.)
When you perform an operation alongside a string Java will perform that operation as if the operands were strings.
In your System.out.println() calls you don't need to redo the calculations, just print out the variables "tax" and "totalBill". (This will solve the problem of printing '907')
You will only ever get integer values because you are using int type for everything. If you want to have decimals to indicate cents you should be using type double.

Categories

Resources