Using double to temporarily store currency values? [duplicate] - java

This question already has answers here:
Why not use Double or Float to represent currency?
(16 answers)
Closed 8 years ago.
it's pretty clear why double & co. are not a good choice when it comes to handling currency.
I'm wondering though, since the issue only arises when calculations are performed on the value, am I correct by assuming that there is no problem at all to just store a currency value in a double?
For example:
1. Value gets loaded from any given source into a double
2. Value gets modified, directly typed in by the user.
3. Value gets stored to disk in a suitable format.
In the above example the double is just a way to store the value in memory, and thus shouldn't present any of the problems that arise if calculates are performed on the value.
Is this correct?
And, if correct, wouldn't it be better to use currency specific types, only when performing calculations?
Instead of loading 1000 BigDecimals from a database one could load 1000 doubles. Then, when necessary, define a BigDecimal, do the calculations and just keep the resulting double in memory.

No, it still causes problems, even if you don't perform any calculations. The problem is that the value you store might not be exactly representable as a double, so even if you just store it and read it back, you might not get back what you stored.
If you store 0.1 in a double, for instance, you'll find it's not actually 0.1 stored at all, because you can't represent 0.1 exactly in binary.

No. A double is never the correct type to store a currency value. Doubles are floating point values, that is, they are basically numbers of the form x * 2^y, where x and y are integers. Thus, some values, such as 0.10 (10 cents) have no exact representation as a double.

The problem here is that when you save say 10.12 in a double variable it may not have a exact double representation, so the java runtime will save it as a closest possible double representation, say 10.1199999999999 or 10.1200000000001 (just an example, I am not sure, have to test). So you get the point, as soon as you put the value in a double variable the currency value is approximated. However, that being said, you can still use a double for calculations and then use appropriate formatting while printing out the values or writing to file, such that the non-significant digits are hidden, depending on your application.

Related

How to round doubles to a specified decimal place without Libraries?

Basically I'm supposed to write a method, that uses a double "x" and an int "y" and rounds (>=5 upwards, <5 downwards) "x" to the decimal place specified by y (between 1-8). The method is supposed to return a double. However since I just started I don't have a clue how to achieve this. The exercise prior to this one way easier.
If read answers to similar question but they are not quit what I need, because I can't use the Math library or other libraries. I'm allowed to make auxiliary methods to substitute this.
Rounding like that with double isn't going to work. Doubles and floats are represented with a fixed number of bits of data, and work in binary not decimal. That means that some numbers can't be represented. .1 can't be stored exactly.
In order to do this, you need to do use BigDecimal, which is a class that can store any exact number. Math using BigDecimal is less efficient, but it doesn't have the accuracy issues of doubles.

Can a double initialized with a small whole number value be used with accuracy in a BigDecimal context?

It is well documented that using a double can lead to inaccuracies and that BigDecimal guarantees accuracy so long as there are no doubles in the mix.
However, is accuracy guaranteed if the double in question is a small whole number?
For example, although the following will be inaccurate/unsafe:
BigDecimal bdDouble = new BigDecimal(0.1d); // 0.1000000000000000055511151231257827021181583404541015625
will the following always be accurate/safe?
BigDecimal bdDouble = new BigDecimal(1.0d); // 1
Is it safe to assume that small whole number doubles are safe to use with BigDecimals - if so, what is the smallest whole number that would introduce an inaccuracy?
>> Additional info in response to initial answers:
Thanks for the answers. Very helpful.
Just to add a little more detail, I have a legacy interface which supplies doubles, but I can be certain that these doubles will represent whole numbers having being themselves converted from Strings to doubles via Double.parseDouble(String) where the String is a guaranteed whole number representation.
I do not want to create a new interface which passes me Strings or BigDecimals if I can avoid it.
I can immediately convert the double to a BigDecimal on my side of the interface and make all internal calculations using BigDecimal calls, but I want to be sure that is as safe as creating a new BigDecimal/String interface.
Given that in my original example using 0.1d does not accurately result in 0.1, as shown by the fact that the actual BigDecimal is 0.1000000000000000055511151231257827021181583404541015625, it appears that some fractions will introduce an inaccuracy.
On the other hand, given that in my original example using 1.0d does accurately results in 1, it appears that whole numbers retain accuarcy. It appears that this is guaranteed up to a value of 2^53, if I understand your answers correctly.
Is that a correct assumption?
The BigDecimal aspect isn't as relevant to this question as "what is the range of integers that can be exactly represented in double?" - in that every finite double value can be represented exactly by BigDecimal, and that's the value you'll get if you call the BigDecimal(double) constructor. So you can be confident that if the value you wish to represent is an integer which is exactly representable by a double, if you pass that double to the BigDecimal constructor, you'll get a BigDecimal which exactly represents the same integer.
The significand of a double is 52 bits. Due to normalization, that means you should expect to be able to store integer values in the range [-253, 253] exactly. Those are pretty large numbers.
Of course, if you're only in the business of representing integers, it's questionable as to why you're using double at all... and you need to make sure that any conversions you're using from original source data to double aren't losing any information loss - but purely on the matter of "what range of integers are exactly representable as double values" I believe the above is correct...
A short answer is no. Because of the way a floating point variable is stored in memory there is no "small" value 0.000001 uses the same number of bits as 100000, every value is represented in the same way 0.xxx..eyy
A better way to initialize a BigDecimal is to initialize it with a string.
BigDecimal bdDouble = new BigDecimal("0.1");

Value changes when using double to store the value in c++ but remains same in java

I have similar code in c++ and java. There is a call by value to a double variable. I pass on a value of 1680.175 to both the codes. I can see during debugging that the value when passed changes to 1680.1749999999902 in c++ while it remains the same in java. I have to round a value after two places of decimal and therefore the codes give different result.
The value didn't change at all, you just printed it such that the extra decimals showed. The value 1680.175 does not have an exact representation in the double floating-point notation and the closest value is 1680.1749999999902. The same thing goes on in Java.
A double precision value has mantissa and exponent. Internally 1680.175 may be stored as 1680.1749999999902 or say 1680.1750001002 etc, i.e. close to your actual value. If precision is important then provide extra significant digits after decimal point as well.

How to avoid Double values getting stored in 1Ex format?

I am having a double variable:
private double b=0.0;
I am taking value of a certain field in b (the value is between 0.0 to 9.99999999). Mostly, user enters value between 0.0 to 1.0.
When I am saving the value from user in 'b', and if the value is 0.000001, then it is getting saved as 1E-6 and next time displayed as same on the screen (this is because b is Double).
Is there any way (just by calling some method) in Java, that I can avoid the conversion of value to 1E-6 format? I want to save the value as entered by user only (0.000001).
The double isn't actually "saved" as a string at all. That's just a matter of formatting - for which you should see DecimalFormat. However, it definitely won't be exactly 0.000001 because that number isn't exactly representable as a double. I would strongly recommend that you use BigDecimal instead when precise decimal values matter (as it sounds like they do here).
It's true that the number isn't stored in memory using the scientific (E) notation.
You can demonstrate this to yourself by formatting the number differently when you output it:
#Test
public void testLittle() {
double myNum = 0.000001;
System.out.printf("%f \n",myNum);
}
You should definitely heed other advice posted in answers here and use BigDecimal if you really want the output to match the input, since some floating-point values aren't what
you think they are when representing them in a computer. (ref: IEEE-754)
The "Java Puzzlers" presentations sometimes discuss these odd behaviors and are always a fun way to learn. (See this talk from Google I/O 2011, a bit after 3 minutes in)

Four questions - Calculator Application - Android Java

Hey all, I am a total newbie developing an android application, I've been reading 'Sams Teach Yourself Java in 24 hours' and it's a great book. But I have been stuck on a bit where I get the value of a decimal number only editTexts and use java maths to work out my end value.
Is there a way to have an editText input straight to a float or double variable rather than to a string and then from a string to a double?
Are there any real issues with converting between a string and a double or float or will the values remain the same and not be polluted.
Differences / pros and cons of using a doble as opposed to a float.
Best way to input a fraction value from the user?
Thanks for any help. Have a good day.
No, you can't.
Yes. If your string is, say, an ID and reads like "0029482", after you turn it into an integer it will read "29482" and probably will be invalid. Strings can be longer than doubles or floats, and if you have a value like "0.12345678901234567890123456789" in a string, you will lose a lot of precision by converting that to a double.
Doubles use double the number of bits (hence the name), and can therefore hold more precision.
Accept the denominator and numerator integers, and store them in a custom class.
No. You could write your own subclass that makes it seem like that is what's happening, but at some point somewhere in the chain you have to do a conversion from character/text data to numerical data.
Yes. Primitive floating-point types use IEEE-754 to encode decimal numbers in binary. The encoding provides very good precision, but it is not exact/cannot exactly represent many possible numbers. So if you parse from a string to a primitive floating-point type, and then back to string again, you may get something that is different from your input string.
A double uses twice as many bits to encode the number as a float, and thus is able to maintain a greater degree of precision. It will not, however, remove the issues discussed in #2. If you want to remove those issues, consider using something like BigDecimal to represent your numbers instead of primitive types like float or double.
Read the whole thing as a string, split() it on the '/' character, and then store each part as an integer (or BigInteger). If you need to display it as a decimal, use BigDecimal to perform the division.
I'd just like to add that if you are looking for an alternative to double or float that doesn't entail loss of precision when converting between strings and numeric form, look at these:
The standard java.math.BigDecimal class represents an arbitrary precision scaled number; i.e. an arbitrary precision integer multiplied (scaled) by a fixed integer power of 10.
The Apache dfp package contains implementations of decimal-based floating numbers.
However, I'd steer clear of both of this topic for now, and implement using float or double. (I take it that your real aim is to learn how to write Java, not to build the world's greatest calculator app.)

Categories