Understanding of a float counter - java

I have following simple code:
for (float i=0; i<1f; i+=0.1) {
System.out.println(i);
}
I have just got following results:
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.70000005
0.8000001
0.9000001
But I can't understand why there is. Please, I hope you can tell me. Thank you.

From The Floating-Point Guide:
Why don’t my numbers, like 0.1 + 0.2 add up to a nice round 0.3, and
instead I get a weird result like 0.30000000000000004?
Because internally, computers use a format (binary floating-point)
that cannot accurately represent a number like 0.1, 0.2 or 0.3 at all.
When the code is compiled or interpreted, your “0.1” is already
rounded to the nearest number in that format, which results in a small
rounding error even before the calculation happens.

Well because with the way float has been implemented there usually is a very small deviation from the mathematical 0.1f you are incrementing with, so actually you are incrementing with just a small amount over that.
A solution would be to use:
BigDecimal
EDIT:
Michael posted a better description of your problem, but still you should take a look at BigDecimal.

It's because the way computers store floating point numbers.
For detailed information you could have a look at the IEEE 754.
This is related to a numerical problem.

You almost always need to constrain the number of decimal places when printing floats or doubles.
Java's take on printf from C
for (float i = 0; i < 1f; i += 0.1) {
System.out.printf("%.1f\n", i);
}
DecimalFormat to print up to 1 decimal place if necessary
DecimalFormat format1 = new DecimalFormat("#.#");
for (float i = 0; i < 1f; i += 0.1) {
System.out.println(format1.format(i));
}
DecimalFormat to print 1 decimal place always
DecimalFormat format2 = new DecimalFormat("0.0");
for (float i = 0; i < 1f; i += 0.1) {
System.out.println(format2.format(i));
}

Related

How get .average using stream and OptionalDouble to get below desired output? and using getusDouble [duplicate]

So I have a double set to equal 1234, I want to move a decimal place over to make it 12.34
So to do this I multiply .1 to 1234 two times, kinda like this
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.println(x);
This will print the result, "12.340000000000002"
Is there a way, without simply formatting it to two decimal places, to have the double store 12.34 correctly?
If you use double or float, you should use rounding or expect to see some rounding errors. If you can't do this, use BigDecimal.
The problem you have is that 0.1 is not an exact representation, and by performing the calculation twice, you are compounding that error.
However, 100 can be represented accurately, so try:
double x = 1234;
x /= 100;
System.out.println(x);
which prints:
12.34
This works because Double.toString(d) performs a small amount of rounding on your behalf, but it is not much. If you are wondering what it might look like without rounding:
System.out.println(new BigDecimal(0.1));
System.out.println(new BigDecimal(x));
prints:
0.100000000000000005551115123125782702118158340454101562
12.339999999999999857891452847979962825775146484375
In short, rounding is unavoidable for sensible answers in floating point whether you are doing this explicitly or not.
Note: x / 100 and x * 0.01 are not exactly the same when it comes to rounding error. This is because the round error for the first expression depends on the values of x, whereas the 0.01 in the second has a fixed round error.
for(int i=0;i<200;i++) {
double d1 = (double) i / 100;
double d2 = i * 0.01;
if (d1 != d2)
System.out.println(d1 + " != "+d2);
}
prints
0.35 != 0.35000000000000003
0.41 != 0.41000000000000003
0.47 != 0.47000000000000003
0.57 != 0.5700000000000001
0.69 != 0.6900000000000001
0.7 != 0.7000000000000001
0.82 != 0.8200000000000001
0.83 != 0.8300000000000001
0.94 != 0.9400000000000001
0.95 != 0.9500000000000001
1.13 != 1.1300000000000001
1.14 != 1.1400000000000001
1.15 != 1.1500000000000001
1.38 != 1.3800000000000001
1.39 != 1.3900000000000001
1.4 != 1.4000000000000001
1.63 != 1.6300000000000001
1.64 != 1.6400000000000001
1.65 != 1.6500000000000001
1.66 != 1.6600000000000001
1.88 != 1.8800000000000001
1.89 != 1.8900000000000001
1.9 != 1.9000000000000001
1.91 != 1.9100000000000001
NOTE: This has nothing to do with randomness in your system (or your power supply). This is due to a representation error, which will produce the same outcome every time. The precision of double is limited and in base 2 rather than base 10, so numbers which can be precisely represented in decimal often cann't be precisely represented in base 2.
No - if you want to store decimal values accurately, use BigDecimal. double simply can't represent a number like 0.1 exactly, any more than you can write the value of a third exactly with a finite number of decimal digits.
if it's just formatting, try printf
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.printf("%.2f",x);
output
12.34
In financial software it is common to use integers for pennies. In school, we were taught how to use fixed-point instead of floating, but that is usually powers of two. Storing pennies in integers might be called "fixed point" as well.
int i=1234;
printf("%d.%02d\r\n",i/100,i%100);
In class, we were asked in general what numbers can be exactly represented in a base.
For base=p1^n1*p2^n2... you can represent any N where N=n*p1^m1*p2^m2.
Let base=14=2^1*7^1... you can represent 1/7 1/14 1/28 1/49 but not 1/3
I know about financial software -- I converted Ticketmaster's financial reports from VAX asm to PASCAL. They had their own formatln() with codes for pennies. The reason for the conversion was 32 bit integers were no longer enough. +/- 2 billion pennies is $20 million and that overflowed for the World Cup or Olympics, I forgot.
I was sworn to secrecy. Oh well. In academea, if it's good you publish; in industry, you keep it secret.
you can try integer number representation
int i =1234;
int q = i /100;
int r = i % 100;
System.out.printf("%d.%02d",q, r);
This is caused by the way computers store floating-point numbers. They don't do so exactly. As a programmer, you should read this floating-point guide to familiarize yourself with the trials and tribulations of handling floating-point numbers.
Funny that numerous posts mention to use BigDecimal but no-one bothers to give the correct answer based on BigDecimal? Because even with BigDecimal, you can still go wrong, as demonstrated by this code
String numstr = "1234";
System.out.println(new BigDecimal(numstr).movePointLeft(2));
System.out.println(new BigDecimal(numstr).multiply(new BigDecimal(0.01)));
System.out.println(new BigDecimal(numstr).multiply(new BigDecimal("0.01")));
Gives this output
12.34
12.34000000000000025687785232264559454051777720451354980468750
12.34
The BigDecimal constructor specifically mentions that it is better to use String constructor than a numeric constructor. Ultimate precision is also influenced by the optional MathContext.
According to the BigDecimal Javadoc it is possible to create a BigDecimal which is exactly equal to 0.1, provided you use the String constructor.
Yes, there is. With each double operation you may lose accuracy but the amount of accuracy differs for each operation and can be minimized by choosing the right sequence of operations. For example when multiplying set of numbers, it is best to sort set by exponent before multiplying.
Any decent book on number crunching describes this. For example:
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
And to answer your question:
Use divide instead of multiply, this way you get correct result.
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x / 10.0;
}
System.out.println(x);
No, as Java floating point types (indeed all floating point types) are a trade-off between size and precision. While they're very useful for a lot of tasks, if you need arbitrary precision, you should use BigDecimal.

How to achieve "1 - 1/3 - 1/3 - 1/3 = 0"? [duplicate]

I have a very annoying problem with long sums of floats or doubles in Java. Basically the idea is that if I execute:
for ( float value = 0.0f; value < 1.0f; value += 0.1f )
System.out.println( value );
What I get is:
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.70000005
0.8000001
0.9000001
I understand that there is an accumulation of the floating precision error, however, how to get rid of this? I tried using doubles to half the error, but the result is still the same.
Any ideas?
There is a no exact representation of 0.1 as a float or double. Because of this representation error the results are slightly different from what you expected.
A couple of approaches you can use:
When using the double type, only display as many digits as you need. When checking for equality allow for a small tolerance either way.
Alternatively use a type that allows you to store the numbers you are trying to represent exactly, for example BigDecimal can represent 0.1 exactly.
Example code for BigDecimal:
BigDecimal step = new BigDecimal("0.1");
for (BigDecimal value = BigDecimal.ZERO;
value.compareTo(BigDecimal.ONE) < 0;
value = value.add(step)) {
System.out.println(value);
}
See it online: ideone
You can avoid this specific problem using classes like BigDecimal. float and double, being IEEE 754 floating-point, are not designed to be perfectly accurate, they're designed to be fast. But note Jon's point below: BigDecimal can't represent "one third" accurately, any more than double can represent "one tenth" accurately. But for (say) financial calculations, BigDecimal and classes like it tend to be the way to go, because they can represent numbers in the way that we humans tend to think about them.
Don't use float/double in an iterator as this maximises your rounding error. If you just use the following
for (int i = 0; i < 10; i++)
System.out.println(i / 10.0);
it prints
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
I know BigDecimal is a popular choice, but I prefer double not because its much faster but its usually much shorter/cleaner to understand.
If you count the number of symbols as a measure of code complexity
using double => 11 symbols
use BigDecimal (from #Mark Byers example) => 21 symbols
BTW: don't use float unless there is a really good reason to not use double.
It's not just an accumulated error (and has absolutely nothing to do with Java). 1.0f, once translated to actual code, does not have the value 0.1 - you already get a rounding error.
From The Floating-Point Guide:
What can I do to avoid this problem?
That depends on what kind of
calculations you’re doing.
If you really need your results to add up exactly, especially when you work with money: use a special decimal datatype.
If you just don’t want to see all those extra decimal places: simply format your result rounded to a fixed
number of decimal places when
displaying it.
If you have no decimal datatype available, an alternative is to work
with integers, e.g. do money
calculations entirely in cents. But
this is more work and has some
drawbacks.
Read the linked-to site for detailed information.
Another solution is to forgo == and check if the two values are close enough. (I know this is not what you asked in the body but I'm answering the question title.)
For the sake of completeness I recommend this one:
Shewchuck, "Robust Adaptive Floating-Point Geometric Predicates", if you want more examples of how to perform exact arithmetic with floating point - or at least controlled accuracy which is the original intention of author, http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf
I had faced same issue, resolved the same using BigDecimal. Below is the snippet which helped me.
double[] array = {45.34d, 45000.24d, 15000.12d, 4534.89d, 3444.12d, 12000.00d, 4900.00d, 1800.01d};
double total = 0.00d;
BigDecimal bTotal = new BigDecimal(0.0+"");
for(int i = 0;i < array.length; i++) {
total += (double)array[i];
bTotal = bTotal.add(new BigDecimal(array[i] +""));
}
System.out.println(total);
System.out.println(bTotal);
Hope it will help you.
You should use a decimal datatype, not floats:
https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
package loopinamdar;
import java.text.DecimalFormat;
public class loopinam {
static DecimalFormat valueFormat = new DecimalFormat("0.0");
public static void main(String[] args) {
for (float value = 0.0f; value < 1.0f; value += 0.1f)
System.out.println("" + valueFormat.format(value));
}
}
First make it a double. Don't ever use float or you will have trouble using the java.lang.Math utilities.
Now if you happen to know in advance the precision you want and it is equal or less than 15, then it becomes easy to tell your doubles to behave. Check below:
// the magic method:
public final static double makePrecise(double value, int precision) {
double pow = Math.pow(10, precision);
long powValue = Math.round(pow * value);
return powValue / pow;
}
Now whenever you make an operation, you must tell your double result to behave:
for ( double value = 0.0d; value < 1.0d; value += 0.1d )
System.out.println( makePrecise(value, 1) + " => " + value );
Output:
0.0 => 0.0
0.1 => 0.1
0.2 => 0.2
0.3 => 0.30000000000000004
0.4 => 0.4
0.5 => 0.5
0.6 => 0.6
0.7 => 0.7
0.8 => 0.7999999999999999
0.9 => 0.8999999999999999
1.0 => 0.9999999999999999
If you need more than 15 precision then you are out of luck:
for ( double value = 0.0d; value < 1.0d; value += 0.1d )
System.out.println( makePrecise(value, 16) + " => " + value );
Output:
0.0 => 0.0
0.1 => 0.1
0.2 => 0.2
0.3000000000000001 => 0.30000000000000004
0.4 => 0.4
0.5 => 0.5
0.6 => 0.6
0.7 => 0.7
0.8 => 0.7999999999999999
0.9 => 0.8999999999999999
0.9999999999999998 => 0.9999999999999999
NOTE1: For performance you should cache the Math.pow operation in an array. Not done here for clarity.
NOTE2: That's why we never use doubles for prices, but longs where the last N (i.e. where N <= 15, usually 8) digits are the decimal digits. Then you can forget about what I wrote above :)
If you want to keep on using float and avoid accumulating errors by repeatedly adding 0.1f, try something like this:
for (int count = 0; count < 10; count++) {
float value = 0.1f * count;
System.out.println(value);
}
Note however, as others have already explained, that float is not an infinitely precise data type.
You just need to be aware of the precision required in your calculation and the precision your chosen data type is capable of and present your answers accordingly.
For example, if you are dealing with numbers with 3 significant figures, use of float (which provides a precision of 7 significant figures) is appropriate. However, you can't quote your final answer to a precision of 7 significant figures if your starting values only have a precision of 2 significant figures.
5.01 + 4.02 = 9.03 (to 3 significant figures)
In your example you are performing multiple additions, and with each addition there is a consequent impact on the final precision.

Finding ranges of character frequencies [duplicate]

I have a very annoying problem with long sums of floats or doubles in Java. Basically the idea is that if I execute:
for ( float value = 0.0f; value < 1.0f; value += 0.1f )
System.out.println( value );
What I get is:
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.70000005
0.8000001
0.9000001
I understand that there is an accumulation of the floating precision error, however, how to get rid of this? I tried using doubles to half the error, but the result is still the same.
Any ideas?
There is a no exact representation of 0.1 as a float or double. Because of this representation error the results are slightly different from what you expected.
A couple of approaches you can use:
When using the double type, only display as many digits as you need. When checking for equality allow for a small tolerance either way.
Alternatively use a type that allows you to store the numbers you are trying to represent exactly, for example BigDecimal can represent 0.1 exactly.
Example code for BigDecimal:
BigDecimal step = new BigDecimal("0.1");
for (BigDecimal value = BigDecimal.ZERO;
value.compareTo(BigDecimal.ONE) < 0;
value = value.add(step)) {
System.out.println(value);
}
See it online: ideone
You can avoid this specific problem using classes like BigDecimal. float and double, being IEEE 754 floating-point, are not designed to be perfectly accurate, they're designed to be fast. But note Jon's point below: BigDecimal can't represent "one third" accurately, any more than double can represent "one tenth" accurately. But for (say) financial calculations, BigDecimal and classes like it tend to be the way to go, because they can represent numbers in the way that we humans tend to think about them.
Don't use float/double in an iterator as this maximises your rounding error. If you just use the following
for (int i = 0; i < 10; i++)
System.out.println(i / 10.0);
it prints
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
I know BigDecimal is a popular choice, but I prefer double not because its much faster but its usually much shorter/cleaner to understand.
If you count the number of symbols as a measure of code complexity
using double => 11 symbols
use BigDecimal (from #Mark Byers example) => 21 symbols
BTW: don't use float unless there is a really good reason to not use double.
It's not just an accumulated error (and has absolutely nothing to do with Java). 1.0f, once translated to actual code, does not have the value 0.1 - you already get a rounding error.
From The Floating-Point Guide:
What can I do to avoid this problem?
That depends on what kind of
calculations you’re doing.
If you really need your results to add up exactly, especially when you work with money: use a special decimal datatype.
If you just don’t want to see all those extra decimal places: simply format your result rounded to a fixed
number of decimal places when
displaying it.
If you have no decimal datatype available, an alternative is to work
with integers, e.g. do money
calculations entirely in cents. But
this is more work and has some
drawbacks.
Read the linked-to site for detailed information.
Another solution is to forgo == and check if the two values are close enough. (I know this is not what you asked in the body but I'm answering the question title.)
For the sake of completeness I recommend this one:
Shewchuck, "Robust Adaptive Floating-Point Geometric Predicates", if you want more examples of how to perform exact arithmetic with floating point - or at least controlled accuracy which is the original intention of author, http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf
I had faced same issue, resolved the same using BigDecimal. Below is the snippet which helped me.
double[] array = {45.34d, 45000.24d, 15000.12d, 4534.89d, 3444.12d, 12000.00d, 4900.00d, 1800.01d};
double total = 0.00d;
BigDecimal bTotal = new BigDecimal(0.0+"");
for(int i = 0;i < array.length; i++) {
total += (double)array[i];
bTotal = bTotal.add(new BigDecimal(array[i] +""));
}
System.out.println(total);
System.out.println(bTotal);
Hope it will help you.
You should use a decimal datatype, not floats:
https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
package loopinamdar;
import java.text.DecimalFormat;
public class loopinam {
static DecimalFormat valueFormat = new DecimalFormat("0.0");
public static void main(String[] args) {
for (float value = 0.0f; value < 1.0f; value += 0.1f)
System.out.println("" + valueFormat.format(value));
}
}
First make it a double. Don't ever use float or you will have trouble using the java.lang.Math utilities.
Now if you happen to know in advance the precision you want and it is equal or less than 15, then it becomes easy to tell your doubles to behave. Check below:
// the magic method:
public final static double makePrecise(double value, int precision) {
double pow = Math.pow(10, precision);
long powValue = Math.round(pow * value);
return powValue / pow;
}
Now whenever you make an operation, you must tell your double result to behave:
for ( double value = 0.0d; value < 1.0d; value += 0.1d )
System.out.println( makePrecise(value, 1) + " => " + value );
Output:
0.0 => 0.0
0.1 => 0.1
0.2 => 0.2
0.3 => 0.30000000000000004
0.4 => 0.4
0.5 => 0.5
0.6 => 0.6
0.7 => 0.7
0.8 => 0.7999999999999999
0.9 => 0.8999999999999999
1.0 => 0.9999999999999999
If you need more than 15 precision then you are out of luck:
for ( double value = 0.0d; value < 1.0d; value += 0.1d )
System.out.println( makePrecise(value, 16) + " => " + value );
Output:
0.0 => 0.0
0.1 => 0.1
0.2 => 0.2
0.3000000000000001 => 0.30000000000000004
0.4 => 0.4
0.5 => 0.5
0.6 => 0.6
0.7 => 0.7
0.8 => 0.7999999999999999
0.9 => 0.8999999999999999
0.9999999999999998 => 0.9999999999999999
NOTE1: For performance you should cache the Math.pow operation in an array. Not done here for clarity.
NOTE2: That's why we never use doubles for prices, but longs where the last N (i.e. where N <= 15, usually 8) digits are the decimal digits. Then you can forget about what I wrote above :)
If you want to keep on using float and avoid accumulating errors by repeatedly adding 0.1f, try something like this:
for (int count = 0; count < 10; count++) {
float value = 0.1f * count;
System.out.println(value);
}
Note however, as others have already explained, that float is not an infinitely precise data type.
You just need to be aware of the precision required in your calculation and the precision your chosen data type is capable of and present your answers accordingly.
For example, if you are dealing with numbers with 3 significant figures, use of float (which provides a precision of 7 significant figures) is appropriate. However, you can't quote your final answer to a precision of 7 significant figures if your starting values only have a precision of 2 significant figures.
5.01 + 4.02 = 9.03 (to 3 significant figures)
In your example you are performing multiple additions, and with each addition there is a consequent impact on the final precision.

Why java calculation double error? [duplicate]

So I have a double set to equal 1234, I want to move a decimal place over to make it 12.34
So to do this I multiply .1 to 1234 two times, kinda like this
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.println(x);
This will print the result, "12.340000000000002"
Is there a way, without simply formatting it to two decimal places, to have the double store 12.34 correctly?
If you use double or float, you should use rounding or expect to see some rounding errors. If you can't do this, use BigDecimal.
The problem you have is that 0.1 is not an exact representation, and by performing the calculation twice, you are compounding that error.
However, 100 can be represented accurately, so try:
double x = 1234;
x /= 100;
System.out.println(x);
which prints:
12.34
This works because Double.toString(d) performs a small amount of rounding on your behalf, but it is not much. If you are wondering what it might look like without rounding:
System.out.println(new BigDecimal(0.1));
System.out.println(new BigDecimal(x));
prints:
0.100000000000000005551115123125782702118158340454101562
12.339999999999999857891452847979962825775146484375
In short, rounding is unavoidable for sensible answers in floating point whether you are doing this explicitly or not.
Note: x / 100 and x * 0.01 are not exactly the same when it comes to rounding error. This is because the round error for the first expression depends on the values of x, whereas the 0.01 in the second has a fixed round error.
for(int i=0;i<200;i++) {
double d1 = (double) i / 100;
double d2 = i * 0.01;
if (d1 != d2)
System.out.println(d1 + " != "+d2);
}
prints
0.35 != 0.35000000000000003
0.41 != 0.41000000000000003
0.47 != 0.47000000000000003
0.57 != 0.5700000000000001
0.69 != 0.6900000000000001
0.7 != 0.7000000000000001
0.82 != 0.8200000000000001
0.83 != 0.8300000000000001
0.94 != 0.9400000000000001
0.95 != 0.9500000000000001
1.13 != 1.1300000000000001
1.14 != 1.1400000000000001
1.15 != 1.1500000000000001
1.38 != 1.3800000000000001
1.39 != 1.3900000000000001
1.4 != 1.4000000000000001
1.63 != 1.6300000000000001
1.64 != 1.6400000000000001
1.65 != 1.6500000000000001
1.66 != 1.6600000000000001
1.88 != 1.8800000000000001
1.89 != 1.8900000000000001
1.9 != 1.9000000000000001
1.91 != 1.9100000000000001
NOTE: This has nothing to do with randomness in your system (or your power supply). This is due to a representation error, which will produce the same outcome every time. The precision of double is limited and in base 2 rather than base 10, so numbers which can be precisely represented in decimal often cann't be precisely represented in base 2.
No - if you want to store decimal values accurately, use BigDecimal. double simply can't represent a number like 0.1 exactly, any more than you can write the value of a third exactly with a finite number of decimal digits.
if it's just formatting, try printf
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.printf("%.2f",x);
output
12.34
In financial software it is common to use integers for pennies. In school, we were taught how to use fixed-point instead of floating, but that is usually powers of two. Storing pennies in integers might be called "fixed point" as well.
int i=1234;
printf("%d.%02d\r\n",i/100,i%100);
In class, we were asked in general what numbers can be exactly represented in a base.
For base=p1^n1*p2^n2... you can represent any N where N=n*p1^m1*p2^m2.
Let base=14=2^1*7^1... you can represent 1/7 1/14 1/28 1/49 but not 1/3
I know about financial software -- I converted Ticketmaster's financial reports from VAX asm to PASCAL. They had their own formatln() with codes for pennies. The reason for the conversion was 32 bit integers were no longer enough. +/- 2 billion pennies is $20 million and that overflowed for the World Cup or Olympics, I forgot.
I was sworn to secrecy. Oh well. In academea, if it's good you publish; in industry, you keep it secret.
you can try integer number representation
int i =1234;
int q = i /100;
int r = i % 100;
System.out.printf("%d.%02d",q, r);
This is caused by the way computers store floating-point numbers. They don't do so exactly. As a programmer, you should read this floating-point guide to familiarize yourself with the trials and tribulations of handling floating-point numbers.
Funny that numerous posts mention to use BigDecimal but no-one bothers to give the correct answer based on BigDecimal? Because even with BigDecimal, you can still go wrong, as demonstrated by this code
String numstr = "1234";
System.out.println(new BigDecimal(numstr).movePointLeft(2));
System.out.println(new BigDecimal(numstr).multiply(new BigDecimal(0.01)));
System.out.println(new BigDecimal(numstr).multiply(new BigDecimal("0.01")));
Gives this output
12.34
12.34000000000000025687785232264559454051777720451354980468750
12.34
The BigDecimal constructor specifically mentions that it is better to use String constructor than a numeric constructor. Ultimate precision is also influenced by the optional MathContext.
According to the BigDecimal Javadoc it is possible to create a BigDecimal which is exactly equal to 0.1, provided you use the String constructor.
Yes, there is. With each double operation you may lose accuracy but the amount of accuracy differs for each operation and can be minimized by choosing the right sequence of operations. For example when multiplying set of numbers, it is best to sort set by exponent before multiplying.
Any decent book on number crunching describes this. For example:
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
And to answer your question:
Use divide instead of multiply, this way you get correct result.
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x / 10.0;
}
System.out.println(x);
No, as Java floating point types (indeed all floating point types) are a trade-off between size and precision. While they're very useful for a lot of tasks, if you need arbitrary precision, you should use BigDecimal.

Double type array in java giving me a wrong output [duplicate]

So I have a double set to equal 1234, I want to move a decimal place over to make it 12.34
So to do this I multiply .1 to 1234 two times, kinda like this
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.println(x);
This will print the result, "12.340000000000002"
Is there a way, without simply formatting it to two decimal places, to have the double store 12.34 correctly?
If you use double or float, you should use rounding or expect to see some rounding errors. If you can't do this, use BigDecimal.
The problem you have is that 0.1 is not an exact representation, and by performing the calculation twice, you are compounding that error.
However, 100 can be represented accurately, so try:
double x = 1234;
x /= 100;
System.out.println(x);
which prints:
12.34
This works because Double.toString(d) performs a small amount of rounding on your behalf, but it is not much. If you are wondering what it might look like without rounding:
System.out.println(new BigDecimal(0.1));
System.out.println(new BigDecimal(x));
prints:
0.100000000000000005551115123125782702118158340454101562
12.339999999999999857891452847979962825775146484375
In short, rounding is unavoidable for sensible answers in floating point whether you are doing this explicitly or not.
Note: x / 100 and x * 0.01 are not exactly the same when it comes to rounding error. This is because the round error for the first expression depends on the values of x, whereas the 0.01 in the second has a fixed round error.
for(int i=0;i<200;i++) {
double d1 = (double) i / 100;
double d2 = i * 0.01;
if (d1 != d2)
System.out.println(d1 + " != "+d2);
}
prints
0.35 != 0.35000000000000003
0.41 != 0.41000000000000003
0.47 != 0.47000000000000003
0.57 != 0.5700000000000001
0.69 != 0.6900000000000001
0.7 != 0.7000000000000001
0.82 != 0.8200000000000001
0.83 != 0.8300000000000001
0.94 != 0.9400000000000001
0.95 != 0.9500000000000001
1.13 != 1.1300000000000001
1.14 != 1.1400000000000001
1.15 != 1.1500000000000001
1.38 != 1.3800000000000001
1.39 != 1.3900000000000001
1.4 != 1.4000000000000001
1.63 != 1.6300000000000001
1.64 != 1.6400000000000001
1.65 != 1.6500000000000001
1.66 != 1.6600000000000001
1.88 != 1.8800000000000001
1.89 != 1.8900000000000001
1.9 != 1.9000000000000001
1.91 != 1.9100000000000001
NOTE: This has nothing to do with randomness in your system (or your power supply). This is due to a representation error, which will produce the same outcome every time. The precision of double is limited and in base 2 rather than base 10, so numbers which can be precisely represented in decimal often cann't be precisely represented in base 2.
No - if you want to store decimal values accurately, use BigDecimal. double simply can't represent a number like 0.1 exactly, any more than you can write the value of a third exactly with a finite number of decimal digits.
if it's just formatting, try printf
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.printf("%.2f",x);
output
12.34
In financial software it is common to use integers for pennies. In school, we were taught how to use fixed-point instead of floating, but that is usually powers of two. Storing pennies in integers might be called "fixed point" as well.
int i=1234;
printf("%d.%02d\r\n",i/100,i%100);
In class, we were asked in general what numbers can be exactly represented in a base.
For base=p1^n1*p2^n2... you can represent any N where N=n*p1^m1*p2^m2.
Let base=14=2^1*7^1... you can represent 1/7 1/14 1/28 1/49 but not 1/3
I know about financial software -- I converted Ticketmaster's financial reports from VAX asm to PASCAL. They had their own formatln() with codes for pennies. The reason for the conversion was 32 bit integers were no longer enough. +/- 2 billion pennies is $20 million and that overflowed for the World Cup or Olympics, I forgot.
I was sworn to secrecy. Oh well. In academea, if it's good you publish; in industry, you keep it secret.
you can try integer number representation
int i =1234;
int q = i /100;
int r = i % 100;
System.out.printf("%d.%02d",q, r);
This is caused by the way computers store floating-point numbers. They don't do so exactly. As a programmer, you should read this floating-point guide to familiarize yourself with the trials and tribulations of handling floating-point numbers.
Funny that numerous posts mention to use BigDecimal but no-one bothers to give the correct answer based on BigDecimal? Because even with BigDecimal, you can still go wrong, as demonstrated by this code
String numstr = "1234";
System.out.println(new BigDecimal(numstr).movePointLeft(2));
System.out.println(new BigDecimal(numstr).multiply(new BigDecimal(0.01)));
System.out.println(new BigDecimal(numstr).multiply(new BigDecimal("0.01")));
Gives this output
12.34
12.34000000000000025687785232264559454051777720451354980468750
12.34
The BigDecimal constructor specifically mentions that it is better to use String constructor than a numeric constructor. Ultimate precision is also influenced by the optional MathContext.
According to the BigDecimal Javadoc it is possible to create a BigDecimal which is exactly equal to 0.1, provided you use the String constructor.
Yes, there is. With each double operation you may lose accuracy but the amount of accuracy differs for each operation and can be minimized by choosing the right sequence of operations. For example when multiplying set of numbers, it is best to sort set by exponent before multiplying.
Any decent book on number crunching describes this. For example:
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
And to answer your question:
Use divide instead of multiply, this way you get correct result.
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x / 10.0;
}
System.out.println(x);
No, as Java floating point types (indeed all floating point types) are a trade-off between size and precision. While they're very useful for a lot of tasks, if you need arbitrary precision, you should use BigDecimal.

Categories