I have a float to represent the zoom factor on an image.
setZoomPercent( currentZoomPercent - 0.1f );
The trouble I'm having is that the decrementation is giving the following result. How can I avoid this ?
Zoom:100.0
Zoom:99.9
Zoom:99.8
Zoom:99.700005
Zoom:99.600006
Zoom:99.50001
Zoom:99.40001
Zoom:99.30001
Zoom:99.20001
Zoom:99.10001
Zoom:99.000015
Zoom:98.90002
Zoom:98.80002
P.S: I'm guessing it has to do with the binary representation of 0.1 in binary.
You can avoid it by using BigDecimal
BigDecimal d1 = new BigDecimal("100.00");
BigDecimal d2 = new BigDecimal("0.1");
for(int i = 0; i < 100; i++) {
d1 = d1.subtract(d2);
System.out.println(d1);
}
produces
99.90
99.80
99.70
99.60
99.50
99.40
99.30
99.20
...
Related
So I need to calculate a value.
The input I get is this:
a is seed/m2. The value might a for example 56 but it might be 56.7 also.
b is in g's. for instance 600g
c is % value, might be 90.6 also
d is % value, might be 90.6 also
The result I get should be as kg/ha
Regular int does not cut it. The value of (56 * 600 / 100 / 100) / 100
will be 0.0336. I could multiply it with 10000 but I would lose the precision.
I also tried BigDecimal for this but it gave me a ArithmeticException: “Non-terminating decimal expansion; no exact representable decimal result” when I changed the values of my % variables to something else than 100.
What would be the best option to go with this? The calculation was easy to do in exel as it knew how to convert each value automatically, but doing it in Java code is another thing.
My solutions:
int version:
int a = Integer.decode(germinativeSeed.getText().toString());
int b = Integer.decode(seedMass.getText().toString());
int c = Integer.decode(clean.getText().toString());
int d = Integer.decode(germinative.getText().toString());
int result2 = ( a * b / c / d) / 100;
result is 0
BigDecimal solution:
BigDecimal result2;
BigDecimal a = new BigDecimal(germinativeSeed.getText().toString());
BigDecimal b = new BigDecimal(seedMass.getText().toString());
BigDecimal c;
BigDecimal d;
if (clean.getText().toString().equals("")) {
c = new BigDecimal("100");
} else {
c = new BigDecimal(clean.getText().toString());
}
if (germinative.getText().toString().equals("")) {
d = new BigDecimal("100");
} else {
d = new BigDecimal(germinative.getText().toString());
}
BigDecimal hundred = new BigDecimal("100");
BigDecimal test = new BigDecimal("10000");
result2 = a.multiply(b);
result2 = result2.divide(c, 2, RoundingMode.HALF_UP);
result2 = result2.divide(d, 2, RoundingMode.HALF_UP);
result2 = result2.divide(hundred, 2, RoundingMode.HALF_UP);
result2 = result2.multiply(test);
Result is correct with this only if % values are 100%.
double seed = (double) seedInput;
double m2 = (double) m2Input;
double b = (double) bInput; // unit 'g' is not relevant
double c = (double) cInput;
double d = (double) dInput;
double a = seed / m2;
int result2 = ( a * b / c / d) / 100.0;
So I converted everything to double so you won't have problems with implicit conversions to int.
Your problem comes when you have rational numbers like 1/3, this cannot be represented in a bigdecimal, as it has an infinite representation.
If you really need very big precision you should crate a new bigrational class, where you would store a nominator and denominator, and calculate with them. The code would be much mode complicated.
If you don't need that go for doubles.
Try using float or double (preferred double because of the precision).
I am doing a school assignment in which I solve an equation involving coordinates in a circle (r^2 = x^2 + y^2) were r = 1, and you increment through x values solving for y. I am getting a repeating decimals even though I only incrementing in tenths. I have no idea why and have tried it in a few different ways. Here is the code.
double r = 1;
double rSqr;
double x = 1;
double xSqr;
double y;
double ySqr;
double inc = 0.1;
int count = 0;
while(x > -r)
{
x = r - (count * inc);
rSqr = Math.pow(r, 2);
xSqr = Math.pow(x, 2);
ySqr = rSqr - xSqr;
y = Math.sqrt(ySqr);
count++;
System.out.println(x + " " + y);
}
and the output is this
1.0 0.0
0.9 0.4358898943540673
0.8 0.5999999999999999
0.7 0.714142842854285
0.6 0.8
0.5 0.8660254037844386
0.3999999999999999 0.9165151389911681
0.29999999999999993 0.9539392014169457
0.19999999999999996 0.9797958971132712
0.09999999999999998 0.99498743710662
0.0 1.0
-0.10000000000000009 0.99498743710662
-0.20000000000000018 0.9797958971132712
-0.30000000000000004 0.9539392014169457
-0.40000000000000013 0.9165151389911679
-0.5 0.8660254037844386
-0.6000000000000001 0.7999999999999999
-0.7000000000000002 0.7141428428542849
-0.8 0.5999999999999999
-0.9000000000000001 0.43588989435406705
-1.0 0.0
The problem is that double is imprecise. It uses 64 bits to represent decimal numbers; some bits are used for the numeric part, and some for the exponent, but many seemingly simple decimal numbers can not be accurately represented in this way, for example 0.1. See this wiki article for more.
One way around the problem is to display the number using DecimalFormat, which can round the number for presentation purposes. Here's some example code:
public static void main(String[] args) {
DecimalFormat decimalFormat = new DecimalFormat("#0.000");
double d = 1 - .9; // one way to get a repeating decimal floating point number
System.out.println(d);
System.out.println(decimalFormat.format(d));
}
Output:
0.09999999999999998
0.100
It is the IEEE 754 floating point representation.
Use BigDecimal as datatype instead of double to solve your problem.
But take care as BigDecimal is immutable.
BigDecimal r = BigDecimal.ONE;
BigDecimal rSqr;
BigDecimal x = BigDecimal.ONE;
BigDecimal xSqr;
BigDecimal y;
BigDecimal ySqr;
BigDecimal inc = new BigDecimal("0.1");
int count = 0;
while(x.compareTo(r.negate())>0)
{
// i'll let you fill in this part
}
I've found a solution for calculating number of Pi by using BBS algorithm. But I encountered a problem. I'm missing a precision if using a double variable. Is there any suggestion to fix it?
Here is my code:
public class Pi {
public static void main(String[] args) {
int n = 5;
for (int k = 0; k < n; k++) {
int a0 = (int) Math.pow(16, k);
double a1 = (double) 4 / (8 * k + 1);
double a2 = (double) 2 / (8 * k + 4);
double a3 = (double) 1 / (8 * k + 5);
double a4 = (double) 1 / (8 * k + 6);
double a5 = a1 - a2 - a3 - a4;
double a6 = (double) 1 / a0;
double elem = a5 * a6;
System.out.println(new BigDecimal(elem));
}
}
}
If you need the precision of BigDecimal, you need to use it for all calculations. It is not sufficient to convert the result from double to BigDecimal at the end, because the precision is gone by then.
You need to convert all your aX variables to BigDecimal, and replace operators with calls to the corresponding methods of BigDecimal class:
BigDecimal pi = BigDecimal.ZERO;
for (int k = 0; k < n; k++) {
BigDecimal a0 = new BigDecimal(16).pow(k);
BigDecimal a1 = new BigDecimal(4).divide(new BigDecimal(8*k+1), 20, RoundingMode.HALF_UP);
BigDecimal a2 = new BigDecimal(2).divide(new BigDecimal(8*k+4), 20, RoundingMode.HALF_UP);
BigDecimal a3 = new BigDecimal(1).divide(new BigDecimal(8*k+5), 20, RoundingMode.HALF_UP);
BigDecimal a4 = new BigDecimal(1).divide(new BigDecimal(8*k+6), 20, RoundingMode.HALF_UP);
BigDecimal a5 = a1.subtract(a2).subtract(a3).subtract(a4);
BigDecimal a6 = BigDecimal.ONE.divide(a0, 20, RoundingMode.HALF_UP);
pi.add(a5.multiply(a6));
System.out.println(pi);
}
Demo on ideone.
The problem is that you're using doubles during the calculation itself, thus inevitably losing accuracy. Yes, you're using BigDecimal at the end, but only after already destroying data by putting it in doubles.
The solution is to not use doubles at ANY point in the calculation. Use BigDecimal for every step of the way.
To use a metaphor: What you're doing is trying to pour a swimming pool's amount of water into a glass, then pouring the glass into the pool and expecting it to be filled. No, it won't be, because most of the water didn't fit in the glass and just poured onto the ground.
I have this programme:
BigDecimal a = new BigDecimal("0.21556788990002");
System.out.println(a.setScale(2));
I have result 0.21 but when i want to extract just 0.2 i try
for(int i=1; i<10; i++) System.out.println(a.setScale(i));
I have this error when i= 1:
at java.math.BigDecimal.divideAndRound(BigDecimal.java:1439) at
java.math.BigDecimal.setScale(BigDecimal.java:2390) at
java.math.BigDecimal.setScale(BigDecimal.java:2437) at
NewClass.main(NewClass.java:30)
What i can do to extract with i = 1 ?
You need use rounding mode for scale, for Your case it will the following:
System.out.println(a.setScale(1, RoundingMode.FLOOR));
BTW This is similar to
double a = 0.21556788990002;
for (int i = 1; i < 10; i++)
System.out.printf("%." + i + "f%n", a);
prints
0.2
0.22
0.216
0.2156
0.21557
0.215568
0.2155679
0.21556789
0.215567890
you have to use overloaded setScale method which takes rounding as an second argument.
refer to it here
BigDecimal a = new BigDecimal("0.21556788990002");
System.out.println(a.setScale(1,1)); //result 0.2
I think you may use decimal format as well:
BigDecimal a = new BigDecimal("0.21556788990002");
//change any desired format using 0 or #
DecimalFormat dFormat = new DecimalFormat("0.0");
System.out.println(dFormat.format(a)); //< - print 0.2
DecimalFormat dFormat = new DecimalFormat("#.0");
System.out.println(dFormat.format(a)); //< - print .2
DecimalFormat dFormat = new DecimalFormat("0.00");
System.out.println(dFormat.format(a)); //< - print 0.21
I'm trying to round the number down despite the value after the decimal point. The purpose is then to subtract the rounded number from the full number to isolate the decimals as a new value.
DecimalFormat decfom = new DecimalFormat("#.##");
String splitter1 = decfom.format(newdecihole);
DecimalFormat df = new DecimalFormat("##.");
String splitter2 = df.format(newdecihole);
double split1 = Double.parseDouble(splitter1);
double split2 = Double.parseDouble(splitter2);
double splitdeci = split1 - split2;
double finfracti = splitdeci * 8;
What im trying to do is turn the result into whole numbers and 8ths. Everything ive tried works fine until I have a result that rounds up instead of down (which then gives splitdeci a negative value).
Ive tried making split 2 an int but it just rounds it up
Are you looking for
Math.floor
?
http://docs.oracle.com/javase/6/docs/api/java/lang/Math.html#floor(double)
double splitDecimal = split1 - Math.floor(split2);
int eightFraction = Math.round(splitDecimal) * 8;