BigDecimal division is rounding up - java

I'm trying to calculate the following:
(1 - (1/365)) * (1 - (2/365) = 0.99727528617
I would like to store the entire decimal. Here is my code, but it is giving me an answer of 1:
public BigDecimal probability(int t){
BigDecimal probT; // holds our probability of a single (1-(t/365))
BigDecimal result; // holds our result
result = BigDecimal.ONE; // initialize result to 1
// for 1 to t-1
for (int n = 1; n < t; n++){
int numerator = n; // numerator the value of n
int denominator = 365; // denominator 365
// numberator / denominator (round down)
probT = BigDecimal.valueOf(numerator).divide(BigDecimal.valueOf(denominator), RoundingMode.DOWN);
// 1-answer
probT = BigDecimal.ONE.subtract(probT);
// multiply the probabilities together
result = result.multiply(probT);
}
return result;
}
BigDecimal ans2 = bc.probability(3);
System.out.println("P(3) = " + ans2.toString());
Output:
P(3) = 1

That's because the division you are computing is made with a scale of 0. Quoting the method divide(divisor, roundingMode) Javadoc:
Returns a BigDecimal whose value is (this / divisor), and whose scale is this.scale().
In this case, this.scale() refers to the scale of the numerator, which is 0 because the numerator is BigDecimal.valueOf(n), with n being an integer.
You need to change this division to use divide(divisor, scale, roundingMode) instead and specify the scale you want.

From the java doc
When a MathContext object is supplied with a precision setting of 0
(for example, MathContext.UNLIMITED), arithmetic operations are exact,
as are the arithmetic methods which take no MathContext object. (This
is the only behavior that was supported in releases prior to 5.)
As a corollary of computing the exact result, the rounding mode
setting of a MathContext object with a precision setting of 0 is not
used and thus irrelevant. In the case of divide, the exact quotient
could have an infinitely long decimal expansion; for example, 1
divided by 3.
If the quotient has a nonterminating decimal expansion and the
operation is specified to return an exact result, an
ArithmeticException is thrown. Otherwise, the exact result of the
division is returned, as done for other operations.
To fix, you need to do something like this:
// numberator / denominator (round down)
probT = BigDecimal.valueOf(numerator).divide(BigDecimal.valueOf(denominator), 10,RoundingMode.DOWN);
where 10 is precision(decimal places precision) and RoundingMode.DOWN is rounding mode

Related

Taking Modulo of Double NUmber

I have given two number a and b.I have to Calculate (a^b)%1000000007.How Can i calculate for floating point numbers. Ex:
a= 7.654 and b=10000
Here is my Code will % work :
public static double super_pow(double A , long B){
double o=1;
while(B>0){
if((B&1)!=0) o*=A;
A*=A;
B/=2;
o%=mod;
A%=mod;
}
return (o)%mod;
}
Yes, in Java you can use the % operator on floating point types.
You will have problems with the exponent though: You can't use % to reduce the intermediate results because modulo does not distribute over floating point multiplication: (a*b)%c is not (a%c)*(b%c). If you try to compute 7.654^10000 directly you will get infinity; it exceeds the maximum value for double. Even if it didn't you couldn't trust the lowest digits of the result because they are pure noise created by rounding and representation error.
You could use a library that implements exact arithmetic, such as java.math.BigDecimal, but that will cost a lot in terms of execution time and memory. If you think you need to do this calculation as a part of a bigger problem, probably you should take a step back and find another way.
Edit: Here's the result with BigDecimal:
BigDecimal[] divmod = new BigDecimal("7.654").pow(10000)
.divideAndRemainder(new BigDecimal("1000000007"))
return divmod[1].doubleValue() // I get 9.01287592373194E8
In java you can use the modulo operation for floats/doubles (How do I use modulus for float/double?)
If you have to calculate (a^b)%1000000007 you can use double for a and b
(biggest integer that can be stored in a double), this makes exponentiation easier, use the pow() method (http://www.tutorialspoint.com/java/number_pow.htm)
import static java.lang.Math.pow;
public static double super_pow(double A , double B){ //returns long and B is also double
double pow;
double mod = 1000000007.0;
pow = Math.pow(A,B);
mod = pow % 1000000007;
return mod;
}
Alternatively you can typecast (loss of precision possible !) the result of a^b to long and then use
double pow = Math.pow(A,B);
long mod = (long) pow%1000000007L; // the 'L' is important see https://stackoverflow.com/questions/5737616/what-is-the-modulo-operator-for-longs-in-java
return mod; //return a long not double in function
What is the modulo operator for longs in Java?
Is % Modulo?
That depends on language you are using. But In general floating point values does not know modulo operation. You can compute it on your own. Let assume positive floating numbers a=7.654 and b=10000.0 so
d = a/b = 0.0007654 // division
r = d-floor(d) = (0.0007654-0.0) = 0.0007654 // remainder
r = r*b = (0.0007654*10000.0) = 7.654 // rescale back
floor(x) rounds down to nearest less or equal number to x
d holds the floating division result
r holds the remainder (modulo)
Another example a=123.456 and b=65
d = a/b = 1.8993230769230769230769230769231
r = (d-floor(d))*b = 58.456
This can be used for integer and decimal values of a,b but beware the floating point unit performs rounding and can loose precision after few digits... If I remember correctly 64 bit double variables are usually usable maximally up to 18 digits.
[Edit1] hmm you reedited the question to completely different problem
So you are searching for modpow. You can google for java implementation of modpow. For example here
Modular arithmetics and NTT (finite field DFT) optimizations
You can find mine implementation in C++ on 32 bit integer arithmetics but with static modulo prime with specific properties. Still if you change all the
if (DWORD(d)>=DWORD(p)) d-=p;
to d=d%p; it would work for any modulo. you will need modpow,modmul,modadd,modsub.

Math in Java when precision is lost

The below algorithm works to identify a factor of a small number but fails completely when using a large one such as 7534534523.0
double result = 7; // 7534534523.0;
double divisor = 1;
for (int i = 2; i < result; i++){
double r = result / (double)i;
if (Math.floor(r) == r){
divisor = i;
break;
}
}
System.out.println(result + "/" + divisor + "=" + (result/divisor));
The number 7534534523.0 divided by 2 on a calculator can give a decimal part or round it (losing the 0.5). How can I perform such a check on large numbers? Do I have to use BigDecimal for this? Or is there another way?
If your goal is to represent a number with exactly n significant figures to the right of the decimal, BigDecimal is the class to use.
Immutable, arbitrary-precision signed decimal numbers. A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. The value of the number represented by the BigDecimal is therefore (unscaledValue × 10-scale).
Additionally, you can have a better control over scale manipulation, rounding and format conversion.
I don't see what the problem is in your code. It works exactly like it should.
When I run your code I get this output:
7.534534523E9/77359.0=97397.0
That may have confused you, but its perfectly fine. It's just using scientific notation, but there is nothing wrong with that.
7.534534523E9 = 7.534534523 * 109 = 7,534,534,523
If you want to see it in normal notation, you can use System.out.format to print the result:
System.out.format("%.0f/%.0f=%.0f\n", result, divisor, result / divisor);
Shows:
7534534523/77359=97397
But you don't need double or BigDecimal to check if a number is divisible by another number. You can use the modulo operator on integral types to check if one number is divisible by another. As long as your numbers fit in a long, this works, otherwise you can move on to a BigInteger:
long result = 7534534523L;
long divisor = 1;
for (int i = 2; i < result; i++) {
if (result % i == 0) {
divisor = i;
break;
}
}
System.out.println(result + "/" + divisor + "=" + (result / divisor));
BigDecimal is the way to move ahead for preserving high precision in numbers.
DO NOT do not use constructor BigDecimal(double val) as the rounding is performed and the output is not always same. The same is mentioned in the implementation as well. According to it:
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
ALWAYS try to use constructor BigDecimal(String val) as it preserves precision and gives same output each time.

Percentage Calculation for values less than 1 and greater than 0

I am trying to display the percentage using BigDecimal.
for example if i have to do
double val = (9522 / total ) * 100;
System.out.println("Val is :" + val);
where total is 1200000.
I want to display the calculation as a percentage but since the calculation comes to a value less than 0 , I am unable to display the percentage
I also tried
BigDecimal decimal = new BigDecimal((9522 * 100 ) / total);
BigDecimal roundValue = decimal.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("decimal: " + decimal);
System.out.println("roundValue: " + roundValue);
but with the same result.
How can I display the percentage even if it is in Decimals?
The problem is you are doing integer division.
If you want fractional results, you need to do floating point division.
double val = (9522 / (double) total) * 100;
Casting one of your operands to a double will cause Java to perform the correct type of division instead of defaulting to integer division.
You have to inform Java that you want at least one of the numerator or denominator treated as a double, to make sure the result is a double.
This will work:
double val = ((double)9522 / total ) * 100;
System.out.println("Val is :" + val);
BigDecimal decimal = new BigDecimal((9522 * 100 ) / total);
This is not how you do operations on BigDecimal: by the time the BigDecimal is constructed, the precision is gone, because the calculation (9522 * 100 ) / total is done at compile time. That's why the result is the same as with integers: in fact, the entire calculation is done in integers.
Here is how you calculate with BigDecimal objects:
BigDecimal decimal = new BigDecimal(9522)
.multiply(new BigDecimal(100))
.divide(new BigDecimal(total));
If you divide two integer you will get the result truncated. Add a .0 so that it is converted to floating point, and then you will not get a truncated result
new BigDecimal((9522.0 / total) *100);
You may be missing a cast.
double val = (9522 / (double)total ) * 100;
System.out.println("Val is :" + val);
My suspect is that total is an int, and hence 9522/1200000 results in an integer, which is truncated to 0 because the operation implies that the result must be smaller than 1. If you convert total to double the result is going to be a double, and you will be able to retain the decimals.

unexpected results with decimal arithmetic expression

I have some business logic with arithmetic expression and their results are as follows
(10.0 * 20.58)/1.0=205.7999..98
(6.0 * 37.9)/1.0=227.3999..98
(5.0 * 50.0)/1.0=250.0
(10.0 * 37.9)/1.0=379.0
But expected results are
(10.0 * 20.58)/1.0=205.8
(6.0 * 37.9)/1.0=227.4
(5.0 * 50.0)/1.0=250.0
(10.0 * 37.9)/1.0=379.0
I am not clear why we are getting that .999..98 fraction part? Due to that my equals comparison is failing and so business logic. For few cases we are using
amt = (double)Math.round(orderAmt*100000)/100000;
But that is not possible to do the same in each and every place where we have double arithmetic expression.
I want to know why we get such results randomly and is there any possibility to round the results to 5 decimal places instead of rounding every where?
With radix 10 there are some fractions who can't be expressed exactly with a finite number of digits, like for example 1/3 = 0.33333333....
It's the same with radix 2, except that the dividers that produce this kind of results are not the one we are accustomed to, and for example, for 20.58, which is 2058 / 100, it is the case.
Internally, doubles and floats are stored with bits (an not digit), so the exact value of the double or float just can't be stored in the computer's memory. Each time you perform an operation with this value, you get a small shift, because of the approximation, which becomes visible when converting back to decimal format for printing.
It's something you have to pay attention while perfoming computations where precision is important.
So you have two solutions:
Store all your numbers in decimal type and perform all your calculation with it. This will achieve accuracy but for the price of performance.
You can also keep all the calculation with double or float, and format with a fixed number of digits only for printing results.
You could use BigDecimal for roundoff
BigDecimal bd = new BigDecimal((10.0 * 20.58)/1.0) ;
bd = bd.setScale(4, RoundingMode.UP);
use with a static method
public static double round(double value, int digits) {
BigDecimal bd = new BigDecimal(value);
return bd.setScale(digits, RoundingMode.UP).doubleValue();
}
RoundingMode has :
RoundingMode.UP;
RoundingMode.DOWN;
RoundingMode.HALF_DOWN;
RoundingMode.HALF_EVEN;
The basic problem is that
System.out.println(10.0 * 20.58);
prints
205.79999999999998
has a small rounding error due to a representation error in 20.58
You either need to
round the result before comparing.
use a comparision which allows for some error
use BigDecimal (which is over kill in most cases)
use cents instead of dollars i.e. use int or long with fixed precision.
In the last case, the same operation would read
System.out.println(10 * 2058);
prints
20580
where this is 100x the value you need as its fixed precision e.g. cents instead of dollars.
You may want to use double with rounding as below:
double roundingPlaces = 10.0;//use 10.0 for single decimal digit rounding
double a1 = 10.0;
double b1 = 20.58;
double c1 = 1.0;
System.out.println(Math.round((a1*b1*roundingPlaces)/c1)/roundingPlaces);
This prints 205.8.
float fa1 = (float) 10.0;
float fb1 = (float)20.58;
float fc1 = (float)1.0;
System.out.println(fa1*fb1/fc1);
This also prints 205.8
Use float instead of double
http://ideone.com/L9vwR8
System.out.println((float)((10.0f * 20.58f)/1.0f));
output
205.8

double precision in JAVA

I have to round off my result to the nearest fo 0.05 ie(6.34 to 6.35 and 6.37 to 6.4)
So I created myRound function.
When I wrote test to see the function, Its fails.
double rate=14.99;
double percentage=10;
double roundedCost=(rate*percentage)/100; //round off to the nearest value.
double finalRate = rate+myRound(roundedCost,2);
if(finalRate==16.49)
System.out.println("Its proper");
else
System.out.println("Wrong");
The reason is precission value of double.
How to correct the precision.
public double myRound(double value,int roundRange)
{
double hundredMultiple=(float) Math.pow(10, roundRange);
int rangeValue= (int) (value*hundredMultiple);
int tempValue= rangeValue%10;
if(tempValue<5)
tempValue=5-tempValue;
else
tempValue=10-tempValue;
rangeValue=rangeValue+tempValue;
return rangeValue/hundredMultiple;
}
The problem is that you're trying to perform operations which are interested in decimal digits. That doesn't fit well with a binary floating point type. You should use BigDecimal, which is a decimal-based representation.
Just as an idea of why your current scheme won't work, if you write:
double d = 0.1;
the value of d isn't actually 0.1 - it's the closest 64-bit IEEE 754 binary floating point value to 0.1. It'll be very close in value to 0.1, but it won't be 0.1.
A much shorter function is to do.
public static double round(double v, int precision) {
long t = TENS[precision]; // contains powers of ten.
return (double) (long) (v > 0 ? v * t + 0.5 : v * t - 0.5) / t;
}
This works for numbers with less than 18 significant digits (over your precision) e.g. for 2 decimal places, the number should be less than 10^16.
BTW, You should always round the final answer (possibly only round the final answer). This is because x + round(y, 2) may not be equal to round(x + y, 2)

Categories

Resources