I created a program that calculates this algorithm starting at k=1 and ending it k=100:
Here's the code that I've created:
public static void calculatePi() {
BigInteger firstFactorial;
BigInteger secondFactorial;
BigInteger firstMultiplication;
BigInteger firstExponent;
BigInteger secondExponent;
int firstNumber = 1103;
BigInteger firstAddition;
double summationPi = 3.0;
double currentPi = 3.0;
double pi = 3.0;
int secondNumber = 2;
double thirdNumber = Math.sqrt(2.0);
int fourthNumber = 9801;
double prefix = 1;
for(int i=1;i<101;i++){
firstFactorial = factorial(4*i);
secondFactorial = factorial(i);
firstMultiplication = BigInteger.valueOf(26390*i);
firstExponent = exponent(secondFactorial, 4);
secondExponent = exponent(BigInteger.valueOf(396),4*i);
firstAddition = BigInteger.valueOf(firstNumber).add(firstMultiplication);
summationPi = firstFactorial.intValue()*firstAddition.intValue();
summationPi /= firstExponent.intValue()*secondExponent.intValue();
currentPi += summationPi;
}
prefix = secondNumber*thirdNumber;
prefix = prefix/fourthNumber;
summationPi = summationPi*prefix;
pi = 1/summationPi;
System.out.println("Pi is: " + pi);
return;
}
The function exponent(a,b); returns the result of a^b. The function factorial(a) returns the factorial of a. I have proven that both of these functions work perfectly. However, the code seems to mysteriously be returning "NaN." I understand that this happens when something is divided by zero, however I have not been able to find any point at which something is divided by zero. Is there anything else that would cause this/I'm doing wrong?
Note: In the for statement, I'm using i as k in the algorithm.
Thanks in advance!
Problem:
These lines are likely where the error is happening:
summationPi = firstFactorial.intValue()*firstAddition.intValue();
summationPi /= firstExponent.intValue()*secondExponent.intValue();
The reason being that you are calling intValue() on a BigInteger, which is not guaranteed to return the full value (since an int can only hold 32 bits of data. This could also come in to play with storing the result as a double instead of a BigDecimal).
You then take that possible NaN value and use it as the divisor in your division.
Solution:
BigDecimal currentPi = BigDecimal.ONE;
currentPi = currentPi.add(
new BigDecimal(firstFactorial.multiply(firstAddition))
.divide(new BigDecimal(firstExponent.multiply(secondExponent)), new MathContext(10000)));
Notice that I am able to eliminate summationPi by combining multiple lines into one. Also, the MathContext that comes up in the divide() method is set to 10000, this can be changed to any accuracy you want.
For more information on BigDecimal, check the API.
The cause of this problem is at this line:
summationPi /= firstExponent.intValue()*secondExponent.intValue();
where the value of the secondExponent becomes so large as i increases that if you retrieve its int value using the intValue() method, you will get 0.
Related
I've got a really annoying task to do, and stuck with it.
So: I need to write a function which gives back the value of a floating number after the decimal.
For example: the param would be:5.456-> and the returning value should be:456.
I can not use String (of course this would be easy this way).
Do you have any suggestions?
It requires some steps to do it with primitives like float or double. If you were allowed to use BigDecimal, this would just be one line of code.
Given double d = 5.456;
first, cut off the part before the floating point.
do this by int full = (int)d; which will be 5
the subtract full from it: d-full will now be only the part after the point, so .456
now use a loop to multiply the value by 10 until the "after the point" part is 0.
The special thing here is that when you use double, you have floating point precision issues. That means that d will have the value 0.4560000000000004 in between. To solve that, let's introduce an epsilon.
The full code looks like this:
private static final double EPS = 1e-5;
public static void main(String[] args) {
double d = 5.456;
System.out.println(afterDot(d));
}
private static int afterDot(double d) {
d = getDecimals(d);
while(getDecimals(d) > EPS){ //decimals will likely never be 0 because of precision, so compare with a really small EPS instead of 0
d *= 10;
}
//cast the result to an int to cut off the double precision issues
return (int)d;
}
private static double getDecimals(double d) {
int full = (int) d;
d = d-full;
return d;
}
This prints 456. I am very sure this can be optimized somehow, but it's a working first draft.
What you want is the remainder, multiplied by 10 until the remainder is 0. Using BigDecimal to prevent rounding issues that looks like this:
final BigDecimal input = new BigDecimal("5.456");
BigDecimal x = input.remainder(BigDecimal.ONE);
while (x.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) > 0) {
x = x.multiply(new BigDecimal(10));
}
System.out.println(x.longValue());
Here are two ways that don't adjust for floating point anomalies.
double s = 5.456;
System.out.println(s%1);
or
System.out.println(s-(int)s);
both print
0.4560000000000004
Or use BigDecimal and adjust the scale and subtract the integer value.
System.out.println(BigDecimal.valueOf(s)
.setScale(3)
.subtract(BigDecimal.valueOf((int)s)));
prints
.456
I need to cast a double to an int in Java, but the numerical value must always round down. i.e. 99.99999999 -> 99
Casting to an int implicitly drops any decimal. No need to call Math.floor() (assuming positive numbers)
Simply typecast with (int), e.g.:
System.out.println((int)(99.9999)); // Prints 99
This being said, it does have a different behavior from Math.floor which rounds towards negative infinity (#Chris Wong)
To cast a double to an int and have it be rounded to the nearest integer (i.e. unlike the typical (int)(1.8) and (int)(1.2), which will both "round down" towards 0 and return 1), simply add 0.5 to the double that you will typecast to an int.
For example, if we have
double a = 1.2;
double b = 1.8;
Then the following typecasting expressions for x and y and will return the rounded-down values (x = 1 and y = 1):
int x = (int)(a); // This equals (int)(1.2) --> 1
int y = (int)(b); // This equals (int)(1.8) --> 1
But by adding 0.5 to each, we will obtain the rounded-to-closest-integer result that we may desire in some cases (x = 1 and y = 2):
int x = (int)(a + 0.5); // This equals (int)(1.8) --> 1
int y = (int)(b + 0.5); // This equals (int)(2.3) --> 2
As a small note, this method also allows you to control the threshold at which the double is rounded up or down upon (int) typecasting.
(int)(a + 0.8);
to typecast. This will only round up to (int)a + 1 whenever the decimal values are greater than or equal to 0.2. That is, by adding 0.8 to the double immediately before typecasting, 10.15 and 10.03 will be rounded down to 10 upon (int) typecasting, but 10.23 and 10.7 will be rounded up to 11.
(int)99.99999
It will be 99.
Casting a double to an int does not round, it'll discard the fraction part.
Math.floor(n)
where n is a double. This'll actually return a double, it seems, so make sure that you typecast it after.
This works fine int i = (int) dbl;
new Double(99.9999).intValue()
try with this, This is simple
double x= 20.22889909008;
int a = (int) x;
this will return a=20
or try with this:-
Double x = 20.22889909008;
Integer a = x.intValue();
this will return a=20
or try with this:-
double x= 20.22889909008;
System.out.println("===="+(int)x);
this will return ===20
may be these code will help you.
Try using Math.floor.
In this question:
1.Casting double to integer is very easy task.
2.But it's not rounding double value to the nearest decimal. Therefore casting can be done like this:
double d=99.99999999;
int i=(int)d;
System.out.println(i);
and it will print 99, but rounding hasn't been done.
Thus for rounding we can use,
double d=99.99999999;
System.out.println( Math.round(d));
This will print the output of 100.
I have the following sage code that runs instantly (less than a second) and I am trying to convert it to Java (using Java's built-in BigInteger library). But I am not successful.
In short, I initialized N as a BigInteger and delta as double and in order to calculate power (BigInteger ^ double) I converted N to BigDecimal (i.e. new BigDecimal(BigInteger)) and then:
I used this approach but it is too slow (extremely slow).
I used this library but I lost too much precision.
I used this library but I got overflow exception.
N = 16260595201356777876687102055392856230368799478725437225418970788404092751540966827614883675066492383688147288741223234174448378892794567789551235835087027626536919406320142455677084743499141155821894102610573207343199194327005172833989486958434982393556326206485954223151805798621294965926069728816780985683043030371485847746616146554612001066554175545753760388987584593091716701780398711910886679925612838955858736102229719042291682456480437908426849734556856917891628730543729446245974891735371991588505429152639045721840213451875487038496578525189542369448895368117152818687795094021869963915318643663536132393791
delta = 0.26
X = 2*floor(N^delta) # in sage, ^ operator means exponentiation
# similar to ** operator in python
print("X:" + str(x))
Output:
X:32803899270297070621193977210731234596426011189989730481205367370572340252530823123935195892838208219967066426399488721710159859316222019683979411877007525412864
What is the magic? How sage does this? How to convert this code to Java (and be able to get a similar result), there should be some solution.
You can use approach #1 with a workaround. The problem there is that BigFunctions.ln() is not very effective for numbers with large integer part (number of digits to the left of the decimal point). As a workaround I scaled the number so that it contained at most one digit in integer part and compensated that later by adding ln(10) * rescale * delta to the argument of exp().
You should also note that using new BigDecimal(double) constructor leads to loss of precision - read the javadoc for explanation. Instead you should use new BigDecimal(String) (especially if that double comes from some sort of configuration value), or BigDecimal.valueOf(double).
BigInteger N = new BigInteger("16260595201356777876687102055392856230368799478725437225418970788404092751540966827614883675066492383688147288741223234174448378892794567789551235835087027626536919406320142455677084743499141155821894102610573207343199194327005172833989486958434982393556326206485954223151805798621294965926069728816780985683043030371485847746616146554612001066554175545753760388987584593091716701780398711910886679925612838955858736102229719042291682456480437908426849734556856917891628730543729446245974891735371991588505429152639045721840213451875487038496578525189542369448895368117152818687795094021869963915318643663536132393791");
double delta = 0.26;
// this scale is sufficient to get the exact integer part
// it is roughly equal to the number of digits in the result's integer part
final int SCALE = 170;
BigDecimal x = new BigDecimal(N);
BigDecimal y = BigDecimal.valueOf(delta);
int maxIntDigits = 1;
int intDigits = x.precision() - x.scale();
int rescale = Math.max(intDigits - maxIntDigits, 0);
BigDecimal rescaledX = x.scaleByPowerOfTen(-rescale);
BigDecimal z = BigFunctions.exp(
BigFunctions.ln(rescaledX, SCALE)
.add(BigFunctions.ln(BigDecimal.TEN, SCALE).multiply(BigDecimal.valueOf(rescale)))
.multiply(y),
SCALE)
.setScale(0, BigDecimal.ROUND_FLOOR)
.multiply(BigDecimal.valueOf(2));
System.out.println(z);
Output:
32803899270296656086551107648280231830313861082788744611797945239672375099902513857958219091523648839375388564236289659519690404775361188478777234501437677352644
I want to multiply a high precision integer (long or BigInteger) by a small double (think about something > 0 and < 1) and get the arithmetically rounded integer (long or BigInteger) of the exact arithmetic value of the operation as result.
Converting the double to integer does not work, because its fractional value gets lost.
Converting the integer to double, then multiply and converting the result back to integer will not work either, because double is not precise enough.
Of course you could argue, that because the double operand is not precise enough in the first place, it might not matter that the result is not precise with the same order of magnitude, but in this case, it does.
Bonus question:
Using BigDecimal works, but seems to be very inefficient. Converting long to double and then multiplying and converting back seems to run 500 times faster (albeit losing precision) than converting to BigDecimal. Is there a more efficient possibility? Is it possible to gain performance when multiplying several different long each with the same double?
You want to use BigDecimal in order to preserve precision.
BigInteger myBI = new BigInteger("99999999999999999");
Double d = 0.123;
BigDecimal bd = new BigDecimal(myBI);
BigDecimal result = bd.multiply(BigDecimal.valueOf(d));
Using BigDecimal indeed works. You still have to be carefull about using the exact value the double represents and rounding arithmetically.
BigInteger myBI = new BigInteger("1000000000000000000000000000000000000000000000000000000");
double d = 0.1;
BigDecimal bd = new BigDecimal(myBI);
BigInteger doubleWithStringValue = bd.multiply(BigDecimal.valueOf(d)).toBigInteger();
BigDecimal bdresult = bd.multiply(new BigDecimal(d));
BigInteger unrounded = bdresult.toBigInteger();
BigInteger correct = bdresult.add(new BigDecimal("0.5")).toBigInteger(); // this way of rounding assumes positive numbers
BigInteger lostprecision = new BigDecimal(myBI.doubleValue() * d).toBigInteger();
System.out.println("DoubleString: " + doubleWithStringValue);
System.out.println("Unrounded: " + unrounded);
System.out.println("Correct: " + correct);
System.out.println("Lost precision: " + lostprecision);
Output:
DoubleString: 100000000000000000000000000000000000000000000000000000
Unrounded: 100000000000000005551115123125782702118158340454101562
Correct: 100000000000000005551115123125782702118158340454101563
Lost precision: 100000000000000020589742799994816764107083808679919616
The best solution I can see is you use the Math.round function. with code like this.
long l; //your long value
double d;//your fraction
long answer;
answer = Math.round((double)(l * d));
This will give you the answer without a lost prevention error.
The other option would be to truncate it.
same declares as above code.
String s;
s = "" + (l*d);
StringTokenizer token = new StringTokenizer(s);
s = token.nextToken();
answer = Long(s);
Double has a precission of 52 bit. How about:
multiplying your double by (1<<52)
convert double to BigInteger (no loss as full precision is on left of decimal point)
multiply with other BigIngeger
partially correct binary exponent of result (BigInteger>>51)
If odd, do your rounding by adding 1 or BigInteger.Sign (depending on your preferences of rounding)
Finally shift result one more bit (BigInteger>>1)
BigInteger myBI = BigInteger("99999999999999999");
Double d = 0.123;
BigInteger bigDouble = (BigInteger)(d * ((ulong)1 << 52));
BigInteger result = (myBI * bigDouble) >> 51;
if (!result.IsEven)
result += result.Sign;
result = result >> 1;
I have the following code :
Double x = 17.0;
Double y = 0.1;
double remainder = x.doubleValue() % y.doubleValue();
When I run this I get remainder = 0.09999999999999906
Any idea why??
I basically need to check that x is fully divisible by y. Can you suggest alternative ways to do that in java.
Thanks
Because of how floating-point numbers are represented.
If you want exact values, use BigDecimal:
BigDecimal remainder = BigDecimal.valueOf(x).remainder(BigDecimal.valueOf(y));
Another way to to that is to multiple each value by 10 (or 100, 1000), cast to int, and then use %.
You need to compare your result which allows for rounding error.
if (remainder < ERROR || remainder > 0.1 - ERROR)
Also, don't use Double when you mean to use double
Expecting precise results from double arithmetic is problematic on computers. The basic culprit is that us humans use base 10 mostly, whereas computers normally store numbers in base 2. There are conversion problems between the two.
This code will do what you want:
public static void main(String[] args) {
BigDecimal x = BigDecimal.valueOf(17.0);
BigDecimal y = BigDecimal.valueOf(0.1);
BigDecimal remainder = x.remainder(y);
System.out.println("remainder = " + remainder);
final boolean divisible = remainder.equals(BigDecimal.valueOf(0.0));
System.out.println("divisible = " + divisible);
}