number formatting [duplicate] - java

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why not use Double or Float to represent currency?
I'm learning Java so please bear with me for such a simple question. When given a calculation to calculate interest i have this code inputted:
public double calculateTotal(double rate, int n)
{
amount = amount * Math.pow((1+rate), (n/12));
return amount;
}
This returns the answers I'm looking for but keeps adding 0.000000000001 onto the end.
How would i solve this? A friend advised something called number formatting but i couldn't find a solution.

This problem is related to widely known floating point calculation issue.
One of the solutions could be use of import java.math.BigDecimal
Minimizing the effect of accuracy problems article describes the
problem.
Take a look at this ticket Calculation problem in Java
EDIT
Java does not allow to override operators so the only way to add BigDecimals together is by using add method e.g. (assuming your amount is BigDecimal. Bear in mind that BigDecimal is immutable so whatever is returned from calculateTotal needs to be assigned back to ammount
// you assign result to amount outside calculateTotal
amount.add(new BigDecimal(Math.pow((1+rate), (n/12))));
or
// you assign sum to amount inside calculateTotal
amount = amount.add(new BigDecimal(Math.pow((1+rate), (n/12))));

As it was mentioned before BigDecimal is good option if you need better precision with doubles.
There is nice way to do rounding with BigDecimals. Basically you have to specify scale of the BigDecimal instance. Take a look at this sample code:
BigDecimal decimalOne = new BigDecimal(0.1950);
BigDecimal decimalTwo = decimalOne.setScale(2, BigDecimal.ROUND_HALF_DOWN);
BigDecimal decimalThree = decimalOne.setScale(4, BigDecimal.ROUND_HALF_DOWN);
System.out.println("decimalOne: " + decimalOne);
System.out.println("decimalTwo: " + decimalTwo);
System.out.println("decimalThree: " + decimalThree);
Java 7 would print something like this:
decimalOne: 0.195000000000000006661338147750939242541790008544921875
decimalTwo: 0.20
decimalThree: 0.1950
Please note that BigDecimal instances are immutable and that's why you have to assign result of setScale to new instance (decimalOne will not be changed).
In many financial system doubles are not used to store currency information; long type with specific precision is used instead e.g. for precision 2, value 100 would be 1.00, 122 would be 1.22 etc. That approach simplifies and seeds up calculations but it is not good for all the systems. However for simplicity of that question I won't dive into that subject too much.

Related

How do I use BigDecimal to increase the accuracy of this method?

I have written the following simple function that calculates the arctan of the inverse of an integer. I was wondering how to use BigDecimal instead of double to increase the accuracy of the results. I was also thinking of using a BigInteger to store the growing multiples of xSquare that the "term" value is divided by.
I have limited experience with the syntax for how to perform calculations on BigDecimals. How would I revise this function to use them?
/* Thanks to https://www.cygnus-software.com/misc/pidigits.htm for explaining the general calculation method
credited to John Machin.
*/
public static double atanInvInt(int x) {
// Returns the arc tangent of an inverse integer
/* Terminates once the remaining amount reaches zero or the denominator reaches 2101.
If the former happens, the accuracy should be determined by the number format used, such as double.
If the latter happens, the result should be off by at most one from the correct nearest value
in the seventh decimal place, if allowed by the accuracy of the number format used.
This likely only happens if the integer is 1.
*/
int xSquare = x*x;
double result = ((double)1)/x;
double term = ((double)1)/x;
int divisor = 1;
double midResult;
while ((term > 0)) {
term = term / xSquare;
divisor += 2;
midResult = result - term/divisor;
term = term /xSquare;
divisor += 2;
result = midResult + term/divisor;
if (divisor >= 2101) {
return ((result + midResult) / 2);
}
}
return result;
}
The BigDecimal provides very intuitive wrapper methods to provide all the different operations. you can have something like this to have an arbitrary precision of, for example, 99:
public static void main(String[] args) {
System.out.println(atanInvInt(5, 99));
// 0.197395559849880758370049765194790293447585103787852101517688940241033969978243785732697828037288045
}
public static BigDecimal atanInvInt(int x, int scale) {
BigDecimal one = new BigDecimal("1");
BigDecimal two = new BigDecimal("2");
BigDecimal xVal = new BigDecimal(x);
BigDecimal xSquare = xVal.multiply(xVal);
BigDecimal divisor = new BigDecimal(1);
BigDecimal result = one.divide(xVal, scale, RoundingMode.FLOOR);
BigDecimal term = one.divide(xVal, scale, RoundingMode.FLOOR);
BigDecimal midResult;
while (term.compareTo(new BigDecimal(0)) > 0) {
term = term.divide(xSquare, scale, RoundingMode.FLOOR);
divisor = divisor.add(two);
midResult = result.subtract(term.divide(divisor, scale, RoundingMode.FLOOR));
term = term.divide(xSquare, scale, RoundingMode.FLOOR);
divisor = divisor.add(two);
result = midResult.add(term.divide(divisor, scale, RoundingMode.FLOOR));
if (divisor.compareTo(new BigDecimal(2101)) >= 0) {
return result.add(midResult).divide(two, scale, RoundingMode.FLOOR);
}
}
return result;
}
For anyone who wanted to know why it was beneficial to pose this question to begin with: That is a fair question. I have written a rather long answer to it. I believe that writing this answer helped me to articulate to myself things about the BigDecimal class that are more intuitive now that I have Armando Carballo’s answer than they were before, so writing it was hopefully educational. I can only hope that reading it will be as well, though likely in a different way if at all.
The official documentation lists methods, but it doesn’t explain how they are used in the same way that Armando Carballo’s code demonstrates. For example, while the way the BigDecimal.divide method works is pretty intuitive, there is nothing in the official documentation that says “to take the mean of two numbers, not only should you have BigDecimals for those two numbers, but you should also create a BigDecimal equal to 2 and apply the BigDecimal.divide method to the result of a BigDecimal.add operation with the 2 BigDecimal as the input for the divisor.” This is something that is simple enough to be perfectly intuitive once you see it, but if you’ve never used object-oriented methods for the specific purpose of performing arithmetic before, it may be less intuitive the first time you are trying to figure out how to take the mean.
As another example, consider the idea that to figure out whether a number is greater than or equal to another number, instead of using a Boolean operator on the two numbers, you use a compareTo method that can give three possible outputs on one number with the other number as an input, then apply a Boolean operator to the output of that method. This makes perfect sense once you see it in action and have a quick sense of how the compareTo method works, but may be less obvious when you’re staring at a quick description of the compareTo method in the official documentation, even if the description is clear and you are able to figure out what the compareTo method will output with a given BigDecimal value calling the method and a given BigDecimal input as the comparison value. For anyone who has used compareTo methods with other classes besides BigDecimal extensively, this is probably obvious even if they’re new to the specific class, but if you haven’t used Booleans on the result of ANY compareTo method recently, it’s faster to see it.
When working with ints, you might very well write code a bit like this:
int x = 5;
x = x + 2;
System.out.println(x) // should be 7
Here, the “2” value was never declared to be an int. The result of the addition was the same as if we had declared y=2 and said that x = x+y instead of x = x+2, but with the above lines of code no named variable, or Integer object if we used those instead of primitive ints, was created for the “2”. With BigDecimal, on the other hand, since the BigDecimal.add method requires BigDecimals as inputs, it would be mandatory to create a BigDecimal equal to 2 in order to add 2. I don’t see anything in the official documentation that says “use this as a more accurate substitute for doubles, or for longs if you want something more versatile than BigInteger, but in addition to using it as a substitute for declared variables, also create BigDecimal objects equal to small integers that by themselves wouldn’t call for the use of the BigDecimal class so that you can use them in operations. Both your variables and the small values you are adding to them need to be BigDecimals if you want to use BigDecimals.”
Finally, let me explain something that has the potential to make the BigDecimal class more intimidating than it needs to be. Anyone who has ever worked with primitive arrays and tried to predict in advance at the time the array is created exactly how large it needs to be, or is familiar with how lower-level languages involve certain situations in which a programmer needs to know exactly how many bytes something takes up, may feel the need for caution when dealing with something that seems to demand a specified level of precision upfront. The documentation says this: “If no rounding mode is specified and the exact result cannot be represented, an exception is thrown; otherwise, calculations can be carried out to a chosen precision and rounding mode by supplying an appropriate MathContext object to the operation.” A newbie reading that sentence for the first time may be thinking that they are going to have to think extensively about rounding when writing their code for the first time or else face exceptions as soon as a value cannot be represented exactly, or that they are going to have to read the documentation on the MathContext object as well before using BigDecimal, which in turn might lead to reading IEEE standards that help grant an understanding of floating point numbers but are far removed from what the person actually wanted to code. Seeing that some of the constructors for BigDecimal take arrays as inputs and that others take a MathContext as an input, along with noticing that one of the constructors for the related BigInteger class takes a byte array as the input, may strengthen the feeling that using this object class requires a very fine understanding of the exact number of digits that will be used for the specific calculations the class is used for and that understanding MathContext is more or less essential to even the most basic use of the class. While I’m sure understanding MathContext is helpful, baby’s first BigDecimal project can actually work perfectly well without the need to learn this added functionality at the same time as the first use of the BigDecimal. Reading up on the scale parameter might also lead to the belief by a coder looking up info on the class for the first time that it is necessary to predict the order of magnitude of the answer in advance in order to use the class at all.
Armando Caballo’s commendable answer shows that these concerns of a hypothetical newbie are overblown, as while rounding mode does need to be specified fairly often and a consistent scale is often called as a parameter when using the divide method, the scale parameter is actually a fairly arbitrary specification of the desired accuracy in terms of number of decimal places and not something that requires pinpoint predictions about exactly what numbers the class will handle (unless the ultimate purpose for which the BigDecimal is being used requires a finely controlled level of accuracy, in which case it is fairly easy to specify). An “infinite” series of added and subtracted terms to compute an arc tangent was processed without ever declaring a MathContext object.

Getting wrong answer in double arithmetic in Java [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Double calculation producing odd result
I'm writing a program in Java that deals with a lot of double arithmetic. I eventually get to the point where I need to add 0.6666666666666666 and -0.666666666666667. However, the answer that I get is -3.3306690738754696E-16.
In other words,
double d1 = 0.6666666666666666;
double d2 = -0.666666666666667;
System.out.println(d1 + d2);
prints out "-3.3306690738754696E-16". Why is this happening?
Thank you in advance.
doubles are not perfectly accurate, and not every decimal can be perfectly represented as a double (see this). For all practical purposes, -3.3306690738754696E-16 is 0 *. However, if you need more precision, use BigDecimal. Keep in mind that this alternative will not be nearly as efficient as using primitive doubles. It's up to you to decide if you need this level of accuracy and to make a choice accordingly.
*: Evidently, that number is not exactly zero, but for the majority of real-world calculations and computations, a value that small would be inconsiderable. In meters, this value is smaller than the diameter of protons and neutrons - i.e. very very small. That's what I mean by "for all practical purposes".
double values cannot represent all values precisely and this is such an example. You can use BigDecimal instead:
BigDecimal bd1 = new BigDecimal("0.6666666666666666");
BigDecimal bd2 = new BigDecimal("-0.666666666666667");
System.out.println(bd1.add(bd2));
Output:
-4E-16

Java best type to hold price [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Representing Monetary Values in Java
which java type is good to handle price value? and please tell my why ?
I dont know it is simply question :)
I only know that this type must be "safe". Because if we create shop applicatoion or somethink like that.
ps. I need BEST PRACTICE
and how it present in database ?
you should use BigDecimal when dealing with currencies. Java's native floating point types suffer from the same precision issues as other languages, since some decimals cannot be accurately represented as floating point numbers. Even thought it's not java specific, this is an excellent article which describes the complexities around representing decimal values as floating point numbers.
In general, transient values in your application should always use BigDecimal, only converting to a float when you must (for persistence, or displaying data to a user, etc).
an integer (or long) for the smallest denomenator you care about (cents for USD and EUR)
this is because floating points on computers are inherently inaccurate for decimal values(0.1+0.2 != 0.3)
you only need to translate between cent and main dollar in the UI while the domain calculates everything in cents
Personally, I would use BigDecimal (and so does my company!). I consider float or double bad suggestions because of the way floating-point values are stored in the system and there is a possibility of loss of precision (which you certainly don't want when handling money).
If you're building a financial system, I recommend you create or use your own Java class to represent monetary amounts.
As far as the data type to use to hold a monetary amount, long or BigDecimal.
Here's an example Money class that shows the types of methods you need when working with monetary amounts.
If you use sensible rounding of your results double is works perfectly well and not only the fastest but the simplest to write. This can represent money up to $70 trillion without error. Don't use float as this can only represent up to about $10,000 without error.
If you don't know what sensible rounding to use, BigDecimal or long cents could be a better choice.
You need to use the BigDecimal class.

Using Java doubles (or anything else) to store simple fractions [duplicate]

This question already has answers here:
Division of integers in Java [duplicate]
(7 answers)
Closed 7 years ago.
This seems like a very simple error:
double quarter = 1/4;
Is giving
0.0
Anybody know why this might be happening?
I am trying to store pretty much all the fractions from 1/2 to 1/20 (Just the ones with 1 on the top and in int on the bottom), so I won't be able to input the decimal straight away for all of them.
I've read and heard that floating-point datatypes are not a good way of storing fractions, so is there any other way (in Java)?
Try:
double quarter = 1d/4d;
The division of two integers gives a truncated integer. By putting the d behind the numbers you are casting them to doubles.
For starters, you're trying to divide 1/4 as integer values, and it's truncating it. 1. / 4 will correctly give you 0.25; other ways to express the number 1 as a double include 1d, 1.0, and so on.
Other approaches include:
Use BigDecimal to store values to an exact decimal precision. (For example, this is the preferred way to deal with monetary values.)
Use a Fraction or Rational class, either rolling your own or using one from a library. Apache Commons has Fraction and BigFraction, though their documentation seems a little sketchy.
Java is performing integer division because your denominator is an integer.
Try the following:
double quarter = 1 / 4.0;
Or:
double quarter = 1 / (double) 4;
The reason you're getting 0.0 is because the division is done as an integer division and then the result is converted to float. Try this, for example: double quarter = 1.0/4.0; - you should get (pretty much) the expected result.
However, depending on your requirements, this may not be the best way to deal with the problem. For example, you can't store 1/3 in a decimal. The perfect way would be to store simple fraction as a pair of integers. You can create a class for it (with some arithmetic methods) or start by using a simple array. It all depends on your needs.

How do I round up currency values in Java?

Okay, here's my problem.
Basically I have this problem.
I have a number like .53999999.
How do I round it up to 54 without using any of the Math functions?
I'm guessing I have to multiply by 100 to scale it, then divide?
Something like that?
The issue is with money. let's say I have $50.5399999 I know how to get the $50, but I don't have how to get the cents. I can get the .539999 part, but I don't know how to get it to 54 cents.
I would use something like:
BigDecimal result = new BigDecimal("50.5399999").setScale(2, BigDecimal.ROUND_HALF_UP);
There is a great article called Make cents with BigDecimal on JavaWorld that you should take a look at.
You should use a decimal or currency type to represent money, not floating point.
Math with money is more complex than most engineers think (over generalization)
If you are doing currency calculations, I think you may be delving into problems that seem simple at their surface but are actually quite complex. For instance, rounding methods that are a result of business logic decisions that are repeated often can drastically affect the totals of calculations.
I would recommend looking at the Java Currency class for currency formatting.
Also having a look at this page on representing money in java may be helpful.
If this is homework, showing the teacher that you have thought through the real-world problem rather than just slung a bunch of code together that "works" - will surely be more impressive.
On a side note, I initially was going to suggest looking at the implementation of the Java math methods in the source code, so I took a look. I noticed that Java was using native methods for its rounding methods - just like it should.
However, a look at BigDecimal shows that there is Java source available for rounding in Java. So rather than just give you the code for your homework, I suggest that you look at the BigDecimal private method doRound(MathContext mc) in the Java source.
If 50.54 isn't representable in double precision, then rounding won't help.
If you're trying to convert 50.53999999 to a whole number of dollars and a whole number of cents, do the following:
double d = 50.539999; // or however many 9's, it doesn't matter
int dollars = (int)d;
double frac = d - dollars;
int cents = (int)((frac * 100) + 0.5);
Note that the addition of 0.5 in that last step is to round to the nearest whole number of cents. If you always want it to round up, change that to add 0.9999999 instead of 0.5.
Why would you not want to use any Math functions?
static long round(double a)
-Returns the closest long to the argument.
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html
To represent money I would take the following advice instead of re-inventing the wheel:
http://www.javapractices.com/topic/TopicAction.do?Id=13
Try storing your currency as number of cents (you could abstract this to number of base curreny units) with a long.
Edit: Since this is homework, you may not have control over the types. Consider this a lesson for future projects
long money = 5054;
long cents = money % 100;
long dollars = money / 100; // this works due to integer/long truncation
System.out.printf("$%d.%02.d", dollars, cents);
You need to make the number .535 and compare that with your original number to see if you'll round up or down. Here's how you get .535 from .53999999 (should work for any number):
num = .53999999;
int_num = (int)(num * 100); // cast to integer, however you do it in Java
compare_num = (int_num + 0.5) / 100;
compare_num would be .535 in this case. If num is greater than or equal to compare_num, round up to int_num + 1. Otherwise round down simply to int_num.
Sean seems to have it, except, if you want to impose proper rules then you may want to throw in an if statement like so:
double value = .539999;
int result = (int) (value*100);
if(((value*100)%result)>.5)
result++;
I suggest you use long for rounding a double value. It won't matter for small numbers but could make a difference.
double d = 50.539999;
long cents = (long)(d * 100 + 0.5);
double rounded = cents/100;
What exactly are you trying to do? Are you always trying to go to two digits? Or are you always trying to fix things like 99999 at the end no matter what?
According to the comments, it is in fact the former: rounding to dollars and cents. So indeed just round(100*a)/100 is what you want. (The latter would be much more complicated...)
Finally, if you just want to extract the cents part, the following would work:
dollars_and_cents = round(100*a)/100
cents = (dollars_and_cents-(int)dollars_and_cents)*100
(or does java just have frac? In which case the last line would just be frac(dollars_and_cents)*100.

Categories