BigDecimal doesn't calculate divide - java

I divided 124/13. but the app forced close.
this is my code:
Float x =Float.valueOf(a.getText().toString());
Float y =Float.valueOf(b.getText().toString());
BigDecimal xx= new BigDecimal (x);
BigDecimal yy= new BigDecimal (y);
BigDecimal rx= xx.divide(yy);
res.setText("=" + rx);

It is possible that the app is crashing, because BigDecimal.toString() does something unexpected. Also a, or b or rx may be null.
In any way, I would consider using BigDecimal with the String constructor, such that no rounding errors occur:
String x = a.getText().toString();
String y = b.getText().toString();
BigDecimal xx = new BigDecimal(x);
BigDecimal yy = new BigDecimal(y);
BigDecimal rx = xx.divide(yy);
res.setText("=" + rx.toPlainString());
Also write new BigDecimal(x) instead of new BigDecimal (x). Note the omitted space, that may be the very reason why your app crashes, it is not allowed in Java.

You have encountered:
java.lang.ArithmeticException: Non-terminating decimal expansion;
no exact representable decimal result.
Consider this example, which will yeld this exact exception:
BigDecimal x = new BigDecimal(1);
BigDecimal y = new BigDecimal(3);
BigDecimal result = x.divide(y);
That's because there's no exact representation of 0.3333(3).
What you need to do is to specify rounding and precision:
BigDecimal result = x.divide(y, 10 /*scale*/, RoundingMode.HALF_UP);
System.out.println(result); //will print "0.3333333333"
Also note that you should create the BigDecimal directly from String, as float is not a precise representation. Consider this:
String s = "0.123456789";
System.out.println(Float.parseFloat(s)); //prints 0.12345679
System.out.println(new BigDecimal(s)); //prints 0.123456789
It may be the case that you want an approximate result. Then just go with float or double only:
dobule x = Double.parseDouble(a.getText());
dobule y = Double.parseDouble(b.getText());
res.setText("=" + (x/y));

Related

Java - rounding double to 2 decimal places

I know this question has been asked many times but I'm stuck and I don't know what the correct solution should be. I'm writing a program and there's a lot of numbers multiplication. The result must be rounded to 2 decimal places but sometimes the result is not correct.
For example:
I have two doubles v1=99.338 and v2=732.5.
I want to multiply them and have the result rounded to 2 decimal places.
The correct result is 72765.085 so after rounding it should be 72765.09 however in computer the result is 72765.08499999999 and all the rounding methods give 72765.08 which is obviously wrong.
For example
double x= v1 * v2; //x=72765.08499999999
DecimalFormat dec= new DecimalFormat("0.00");
decsetRoundingMode(RoundingMode.HALF_UP);
String v = dec.format(x);
gives 72765.08. The RoundingMode.CEILING in this example works OK but with other values for v and v2 is wrong.
NumberFormat nf= NumberFormat.getInstance();
nf.setMaximumFractionDigits(2);
nf.format(x);
gives 72765.08.
BigDecimal big = new BigDecimal(x, setScale(2, RoundingMode.HALF_UP);
double v = decWartosc.format(x);
gives v=72765.08.
Any other ideas?
I've tried this in C# and the result is correct.
You must use BigDecimal for the calculation itself.
BigDecimal exact = BigDecimal.valueOf(v1).multiply(BigDecimal.valueOf(v2));
BigDecimal big = exact.setScale(2, RoundingMode.HALF_UP);
System.out.println(big.toString());
First of all 99.337 * 732.5 = 72764.3525, and NOT 72765.085.
Now, this code:
BigDecimal b1 = new BigDecimal("99.337");
BigDecimal b2 = new BigDecimal("732.5");
BigDecimal result = b1.multiply(b2).setScale(2, RoundingMode.HALF_UP);
System.out.println(result);
Outputs:
72764.35

How to get from 10.0/3*3 BigDecimal and double?

double a = 10.0;
double b =3;
double c = a/b;
System.out.println(c*b);//answer = 10.0
BigDecimal bigDecimal1 = BigDecimal.valueOf(c);
BigDecimal bigDecimal2 = new BigDecimal("3");
System.out.println(bigDecimal1.multiply(bigDecimal2));//answer = 10.0000000000000005
I'm trying to make a calculator, but there's a problem with 10/3*3
I don't want to just calculate 10/3*3 this formula, I want to return this formula plus 0.2323232323232 of the float. So use the BigDecimal class. There's something wrong with it
I couldn't get the exact result, that's what I wanted 10,
Rather than get 10.0000000000000005
I believe your problem may be here
double c = a/b;
...
BigDecimal bigDecimal1 = BigDecimal.valueOf(c);
You're expecting that a double can perfectly represent 10/3, and I doubt it can
Maybe try something like this, which always represents numbers as BigDecimal
new BigDecimal("10").divide(new BigDecimal("3"))
At which point you'll notice that 10/3 is not representable as a decimal
Non-terminating decimal expansion; no exact representable decimal result
You need to decide how much precision you want, and then use rounding
new BigDecimal("10")
.setScale(10)
.divide(new BigDecimal("3"), BigDecimal.ROUND_HALF_EVEN)
Or you could use a rational number library, as suggested by Patricia. Perhaps see Is there a commonly used rational numbers library in Java?

Subtract and round double values by multiplier

I have two double values
double a = 1.07522;
double b = 1.0752;
and rounding multiplier value
public static final double ROUND_MULTIPLIER = 100000.0;
So there always should be 5 decimal places.
I need to subtract two double values and get result as a - b = 0.00002.
How can I do this with using ROUND_MULTIPLIER ?
I tried using BigDecimal as
BigDecimal.valueOf(a).subtract(BigDecimal.valueOf(b)).round(new MathContext((int)ROUND_MULTIPLIER));
but it not always works, sometimes return 2E-16, it returns weird value when try add to second value as below
BigDecimal.valueOf(a).subtract(BigDecimal.valueOf(b + 0.00002)).round(new MathContext((int)ROUND_MULTIPLIER));
I need to use ROUND_MULTIPLIER.
I don't understand why you must use ROUND_MULTIPLYER and what the exact reason of it's existance is, so I can only guess.
Forcing the code to use ROUND_MULTIPLYER:
public static final double ROUND_MULTIPLIER = 100000.0;
public void foobar()
{
double a = 1.07522;
double b = 1.0752;
BigDecimal opA = BigDecimal.valueOf(a);
BigDecimal opB = BigDecimal.valueOf(b);
BigDecimal result = opA.subtract(opB);
result = result.multiply(BigDecimal.valueOf(ROUND_MULTIPLIER));
int cutResult = result.intValue();
result = BigDecimal.valueOf(cutResult / ROUND_MULTIPLIER);
System.out.println(result);
}
The output of this is
0.000020
Is that what you want? The code is definitly object to optimization, but I let that up to you to do ;-)
Use bigDEcimal and set the scale giving the number of decimals you need
final BigDecimal a = new BigDecimal(1.07522);
final BigDecimal b = new BigDecimal(1.0752);
final BigDecimal result = a.subtract(b);
int newScale = 10; //10 decimals
System.out.println(result.setScale(newScale, BigDecimal.ROUND_UP));
BigDecimal decimal = new BigDecimal(1.07522);
BigDecimal decimal1 = new BigDecimal(1.0752);
System.out.println(decimal.subtract(decimal1).setScale(5, RoundingMode.DOWN));
BigDecimal is the way to go, but why is the ROUND_MULTIPLIER a double value if you cast it to int anyways. Maybe that is where you get your rounding issues from? Give it a spin with an int-multiplier :)
Edit: using setScale() setting a proper rounding mode is usually a better choice, but you insist on using the multiplier, right?

Difference of Two numbers - BigDecimal

I am just trying to learn more about BigDecimal, but below code makes me confuse.
Double x = 1.2;
String y = "1.2";
BigDecimal a = BigDecimal.ZERO;
BigDecimal b = BigDecimal.ZERO;
a = new BigDecimal(x);
b = new BigDecimal(y);
int res = res = b.compareTo(a);
if(res==1){
System.out.println("Die");
}else if(res ==0){
System.out.println("Live");
}else if (res==-1){
System.out.println("God Loves you");
}
Result = Die
I am not ready to "Die", why BigDecimal is hell bent on killing me.
This statement:
Double x = 1.2;
assigns the nearest double-representable value to 1.2 to x. That's just less than 1.2 - the value 1.2 itself can't be represented exactly in binary.
Now when you create a BigDecimal from that value, that "not quite 1.2" value is retained exactly. From the constructor's documentation:
Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value.
... whereas when you use new BigDecimal("1.2") the result is exactly 1.2 - BigDecimal parses the string, and any decimal string representation can be represented exactly by BigDecimal, as that's the whole point of it.
1.2 is slightly bigger than "the nearest double representation of 1.2" hence res is 1.
a = new BigDecimal(x); // a= 1.1999999999999999555910790149937383830547332763671875
b = new BigDecimal(y); // b=1.2
This is due to conversion issue since translates a double into a BigDecimal which is the exact decimal representation.
int res = res = b.compareTo(a); //res= 1
Because 1.2 as double is not what you expect it to be.
Try this:
BigDecimal a = new BigDecimal(String.valueOf(x));
BigDecimal b = new BigDecimal(y);

Java BigDecimal without E

I have a BigDecimal variable
BigDecimal x = new BigDecimal("5521.0000000001");
Formula:
x = x.add(new BigDecimal("-1")
.multiply(x.divideToIntegralValue(new BigDecimal("1.0"))));
I want to remove the integer part, to get the value x = ("0.0000000001"), but my new value is 1E-10 and not the 0.0000000001.
To get a String representation of the BigDecimal without the exponent part, you can use
BigDecimal.toPlainString(). In your example:
BigDecimal x = new BigDecimal("5521.0000000001");
x = x.add(new BigDecimal("-1").
multiply(x.divideToIntegralValue(new BigDecimal("1.0"))));
System.out.println(x.toPlainString());
prints
0.0000000001
Try using BigDecimal.toPlainString() to get value as plain string as you require.
Perhaps using BigDecimal isn't really helping you.
double d = 5521.0000000001;
double f = d - (long) d;
System.out.printf("%.10f%n", f);
prints
0.0000000001
but the value 5521.0000000001 is only an approximate representation.
The actual representation is
double d = 5521.0000000001;
System.out.println(new BigDecimal(d));
BigDecimal db = new BigDecimal(d).subtract(new BigDecimal((long) d));
System.out.println(db);
prints
5521.000000000100044417195022106170654296875
1.00044417195022106170654296875E-10
I suspect whatever you are trying to is not meaningful as you appear to be trying to obtain a value which is not what you think it is.
If you want to do this at your BigDecimal object and not convert it into a String with a formatter you can do it on Java 8 with 2 steps:
stripTrailingZeros()
if scale < 0 setScale to 0 if don't like esponential/scientific
notation
You can try this snippet to better understand the behaviour
BigDecimal bigDecimal = BigDecimal.valueOf(Double.parseDouble("50"));
bigDecimal = bigDecimal.setScale(2);
bigDecimal = bigDecimal.stripTrailingZeros();
if (bigDecimal.scale()<0)
bigDecimal= bigDecimal.setScale(0);
System.out.println(bigDecimal);//50
bigDecimal = BigDecimal.valueOf(Double.parseDouble("50.20"));
bigDecimal = bigDecimal.setScale(2);
bigDecimal = bigDecimal.stripTrailingZeros();
if (bigDecimal.scale()<0)
bigDecimal= bigDecimal.setScale(0);
System.out.println(bigDecimal);//50.2
bigDecimal = BigDecimal.valueOf(Double.parseDouble("50"));
bigDecimal = bigDecimal.setScale(2);
bigDecimal = bigDecimal.stripTrailingZeros();
System.out.println(bigDecimal);//5E+1
bigDecimal = BigDecimal.valueOf(Double.parseDouble("50.20"));
bigDecimal = bigDecimal.setScale(2);
bigDecimal = bigDecimal.stripTrailingZeros();
System.out.println(bigDecimal);//50.2

Categories

Resources