Why does this return Infinity? (Java) - java

Im trying to find the result of 1/1 + 1/4 + 1/9 + 1/16 + 1/25 ...
These is the lines I wrote that give the result Infinity:
public class BaselProblem {
public static void main(String[] args) {
int testLimit = 100000;
double sum = 0;
for (int i = 1; i<testLimit; i++)
{
sum = sum + 1.0/(i*i);
}
System.out.println(sum);
}
}
Changing 1.0/(i*i) to 1/(1.0*i*i) gives the correct result 1.6449240667982423. Why is it that only the 2nd form work but not the 1st?
Also, because (i*i) > 1, then 1.0/(i*i) should be < 1, so how can it leads to in Infinity?

Because your testLimit as well as your i are defined as int. Since you put the expression i*i in parentheses, it will be calculated first, and will try to find the multiple of two integers - which will reach overflow pretty quickly and reset to zero.
Specifically, when i reaches 2¹⁶, i*i will be 2³². This means 1 followed by 32 zeros in binary, of which, only the 32 zeros are kept, which means zero. (Thanks #templatetypedef).
Therefore, you'll have a number divided by zero, which is infinity.
Change your loop declaration so that i is double. Or multiply by a double (1.0) on the left hand of i*i. This will cause the expression to be changed into double before multiplying by the second i.

Java integer have a maximum value of 2,147,483,647. You're eventually surpassing that maximum with the integer that results from i*i.
If you do 1.0*i*i, you're converting the result to a double which can hold a maximum value of 1.79769313486231570E+308.
Your maximum value for i*i will be 10,000,000 which a double can hold, but an integer can't.

Related

Issue with large number [duplicate]

This question already has answers here:
Counting trailing zeros of numbers resulted from factorial
(10 answers)
Closed 2 years ago.
I'm trying to count the number of trailing zero with a factorial.
e.g
4! = 24 So you retrieve 0.
9! = 362880 So you retrieve 1.
10! = 9! x 10 = 3628800 So you retrieve 2.
11! = 10! x 11 = 3.99168E7 So you retrieve 2.
static double factorial(double n) {
double f = 1;
for(int i = 1 ; i <= n ; i++) {
f *= i;
}
return f;
}
static int numberOfZeros(double f) {
int ten = 1;
int count = 0;
for(;f%Math.pow(10, ten) == 0;count++) {
ten++;
}
return count;
}
this codes are Okay until number n is 22. but when i try to put 23 into then count is 0.
Of course, mathematically 23! has trailing zeros.
You don't need to calculate the factorial to count trailing zeroes.
Just see how many times you can divide by powers of 5 (which is the larger factor of 10). This works since any number with a trailing zero will be divisible by 10. You need to do the powers of 5 to catch those times when 5 occurs more than once.
for 45! = 45/25 = 1 + 45/5 = 9 = 10 zeroes.
for 150! = 150/125 = 1 150/25 = 6, 150/5 = 30 so 1 + 6 + 30 = 37 zeros.
Now all you have to do is code it.
The reason your code isn't working is that a double type can only hold 64 bits. Let's do the calculation:
A bit has two possible values, so 2^64 is the largest number a double could hold... if we aren't accounting for negative numbers. Of course, Java doubles support negative values, so we divide 2^64 (18,446,744,073,709,551,616) by two, and then subtract 1 (Because Java takes one number from the positive range to store zero). As a result, we get 9,223,372,036,854,775,807, which represents the positive bound for the Java double type, or in other words, the biggest positive number a double can store.
Now, 23 factorial is a very big number:
25,852,016,738,884,976,640,000
9,223,372,036,854,775,807
Above is the range for a double. Just by looking at the widths of the numbers, we can see that 23! exceeds the range for a double. Therefore, your double value will overflow and you won't get the right answer.
You should consider using the BigInteger class to handle such large numbers and ensure you are getting accurate answers.
GeeksForGeeks BigInteger tutorial
Java API documentation for BigInteger

why does modulus by a large number seem to give a wrong answer in Java

I am trying to find trailing numbers of zeros in a number, here is my code:
public class TrailingZeroes {
public static void bruteForce(int num){ //25
double fact = num; //25
int numOfZeroes = 0;
for(int i= num - 1; i > 1; i--){
fact = fact * (i);
}
System.out.printf("Fact: %.0f\n",fact); //15511210043330984000000000
while(fact % 10 == 0){
fact = fact / 10;
double factRem = fact % 10;
System.out.printf("Fact/10: %.0f\n",fact); //1551121004333098400000000
System.out.printf("FactRem: %.0f\n",factRem); // 2?
numOfZeroes++;
}
System.out.println("Nnumber of zeroes "+ numOfZeroes); //1
}
}
As you can see the fact%10
You use floating point data type illegally.
The float and double primitive types in Java are floating point numbers, where the number is stored as a binary representation of a fraction and a exponent.
More specifically, a double-precision floating point value such as the double type is a 64-bit value, where:
1 bit denotes the sign (positive or negative).
11 bits for the exponent.
52 bits for the significant digits (the fractional part as a binary).
These parts are combined to produce a double representation of a value.
For a detailed description of how floating point values are handled in Java, see the Section 4.2.3: Floating-Point Types, Formats, and Values of the Java Language Specification.
The byte, char, int, long types are [fixed-point][6] numbers, which are exact representions of numbers. Unlike fixed point numbers, floating point numbers will some times (safe to assume "most of the time") not be able to return an exact representation of a number. This is the reason why you end up with 11.399999999999 as the result of 5.6 + 5.8.
When requiring a value that is exact, such as 1.5 or 150.1005, you'll want to use one of the fixed-point types, which will be able to represent the number exactly.
As has been mentioned several times already, Java has a BigDecimal class which will handle very large numbers and very small numbers.
public static void bruteForce(int num) { //25
double fact = num;
// precision was lost on high i
for (int i = num - 1; i > 1; i--)
fact *= i;
String str = String.format("%.0f", fact); //15511210043330984000000000
System.out.println(str);
int i = str.length() - 1;
int numOfZeroes = 0;
while (str.charAt(i--) == '0')
numOfZeroes++;
System.out.println("Number of zeroes " + numOfZeroes); //9
}

Calculating the nth factorial

Im writing a function that implements the following expression (1/n!)*(1!+2!+3!+...+n!).
The function is passed the arguement n and I have to return the above statement as a double, truncated to the 6th decimal place. The issue im running into is that the factorial value becomes so large that it becomes infinity (for large values of n).
Here is my code:
public static double going(int n) {
double factorial = 1.00;
double result = 0.00, sum = 0.00;
for(int i=1; i<n+1; i++){
factorial *= i;
sum += factorial;
}
//Truncate decimals to 6 places
result = (1/factorial)*(sum);
long truncate = (long)Math.pow(10,6);
result = result * truncate;
long value = (long) result;
return (double) value / truncate;
}
Now, the above code works fine for say n=5 or n= 113, but anything above n = 170 and my factorial and sum expressions become infinity. Is my approach just not going to work due to the exponential growth of the numbers? And what would be a work around to calculating very large numbers that doesnt impact performance too much (I believe BigInteger is quite slow from looking at similar questions).
You can solve this without evaluating a single factorial.
Your formula simplifies to the considerably simpler, computationally speaking
1!/n! + 2!/n! + 3!/n! + ... + 1
Aside from the first and last terms, a lot of factors actually cancel, which will help the precision of the final result, for example for 3! / n! you only need to multiply 1 / 4 through to 1 / n. What you must not do is to evaluate the factorials and divide them.
If 15 decimal digits of precision is acceptable (which it appears that it is from your question) then you can evaluate this in floating point, adding the small terms first. As you develop the algorithm, you'll notice the terms are related, but be very careful how you exploit that as you risk introducing material imprecision. (I'd consider that as a second step if I were you.)
Here's a prototype implementation. Note that I accumulate all the individual terms in an array first, then I sum them up starting with the smaller terms first. I think it's computationally more accurate to start from the final term (1.0) and work backwards, but that might not be necessary for a series that converges so quickly. Let's do this thoroughly and analyse the results.
private static double evaluate(int n){
double terms[] = new double[n];
double term = 1.0;
terms[n - 1] = term;
while (n > 1){
terms[n - 2] = term /= n;
--n;
}
double sum = 0.0;
for (double t : terms){
sum += t;
}
return sum;
}
You can see how very quickly the first terms become insignificant. I think you only need a few terms to compute the result to the tolerance of a floating point double. Let's devise an algorithm to stop when that point is reached:
The final version. It seems that the series converges so quickly that you don't need to worry about adding small terms first. So you end up with the absolutely beautiful
private static double evaluate_fast(int n){
double sum = 1.0;
double term = 1.0;
while (n > 1){
double old_sum = sum;
sum += term /= n--;
if (sum == old_sum){
// precision exhausted for the type
break;
}
}
return sum;
}
As you can see, there is no need for BigDecimal &c, and certainly never a need to evaluate any factorials.
You could use BigDecimal like this:
public static double going(int n) {
BigDecimal factorial = BigDecimal.ONE;
BigDecimal sum = BigDecimal.ZERO;
BigDecimal result;
for(int i=1; i<n+1; i++){
factorial = factorial.multiply(new BigDecimal(i));
sum = sum.add(factorial);
}
//Truncate decimals to 6 places
result = sum.divide(factorial, 6, RoundingMode.HALF_EVEN);
return result.doubleValue();
}

strange number of repetitions in for loop

I wrote this little program to calculate pi.
While playing with the code and trying to find the most exact result, I found a point where my computer couldn't calalculate a result. It could do 33554430 repetitions within seconds, but if i increased the for loop to 33554431 it didn't output anything.
So is 33554430 a special number?
public class CalculatePi{
public static void main(String[] args){
float pi=0;
int sign=1;
for(float i=1; i <= 33554430; i+=2){
pi += (sign*(1.0/i));
sign*= -1;
}
pi *= 4;
System.out.println(pi);
}
}
You are getting and endless loop, because during the comparison i <= 33554431, the int value 33554431 is promoted to a float value which is "too precise" for float and will actually equal to 33554432.
Then, when you try to increase the value by +2, the float just isn't precise enough to increment from the value 33554432. To illustrate my point:
float f = 33554432;
System.out.println(f); //33554432
f += 2;
System.out.println(f); //33554432
So the value f doesn't increase due to its precision limitation. If you'd increase it by, say 11, you'd get 33554444 (and not 33554443) as that is the closest number expressible with that precision.
So is 33554430 a special number?
Sort of, not 33554430 but rather 33554432. First "special number" for float is 16777217, which is the first positive integer that cannot be represented as a float (equals 16777216 as float). So, if you'd increment your i variable by 1, this is the number you'd get stuck on. Now, since you are incrementing by 2, the number you get stuck on is 16777216 * 2 = 33554432.
public class CalculatePi{
public static void main(String[] args){
float pi=0;
int sign=1;
for(float i=1; i <= 33554431; i+=2){
pi += (sign*(1.0/i));
sign*= -1;
if( i > 33554410) System.out.println(i);
}
pi *= 4;
System.out.println(pi);
System.out.println((float)33554431);
System.out.println((float)33554432);
System.out.println((float)33554434);
}
}
You compare float with int in for loop. When you convert 33554431 (it's int value) to float you get 3.3554432E7.
It's about accuracy, precision. When you run:
System.out.println((float)33554431); // -> 3.3554432E7
System.out.println((float)33554432); // -> 3.3554432E7
System.out.println((float)33554434); // -> 3.3554432E7
All 3 prints 3.3554432E7, it means that when you increase float value of 33554432 by 2, you get 3.3554432E7, exactly this same value, and your loop runs forever.
Your loop increments by 2 each time.
2 * 33554430 = 67108860
2 ^ 26 = 67108864
Maybe Java stores floating point numbers in a 32bit system by using 26bits for the mantissa and 6 bits for the exponent?
This version works for both. It's the float loop variable causing problems:
public static void main(String[] args){
float pi=0;
int sign=1;
for(int i=1; i <= 33554430; i+=2){
pi += (sign*(1.0/(float)i));
sign*= -1;
}
pi *= 4;
System.out.println(pi);
}
Probably this is due this issue:
The finite nonzero values of any floating-point value set can all be
expressed in the form s · m · 2(e - N + 1), where s is +1 or -1, m is
a positive integer less than 2N, and e is an integer between Emin =
-(2K-1-2) and Emax = 2K-1-1, inclusive, and where N and K are parameters that depend on the value set.

Adding all numbers from 1 to N which have number of set bits as 2

I have a question where I have to add numbers from 1 to N which have their set bits as 2. Like for N = 5 we should get value 8, as number 3 and 5 have 2 bits set to one. I am implementing the same in java. I am getting the o/p correct for int value but when it comes to the long values, either it's taking a lot of time or freezing, and when I submit the same on code judge sites, it's giving run time exceeded message. Please guide me how may I optimise my code to run it faster, thanks :)
public static void main(String[] args)
{
long n = 1000000L;
long sum = 0;
long start = System.currentTimeMillis();
for(long i = 1L ; i <= n ; i++)
{
if(Long.bitCount(i) == 2)
{
sum += i;
}
}
long end = System.currentTimeMillis();
System.out.println(sum);
System.out.println("time="+(end-start));
}
As #hbejgel notes, there is no point in looping over all numbers and checking their bit count. You can simply construct numbers with 2 bits and add them up.
You can construct a number with 2 bits by picking two different bit positions in the long, the "higher" bit and the "lower" bit":
long i = (1 << higher) + (1 << lower);
So, you can simply loop over all such numbers, until the value you have constructed exceeds your limit:
long sum = 0;
outer: for (int higher = 1; higher < 63; ++higher) {
for (int lower = 0; lower < higher; ++lower) {
long i = (1 << higher) + (1 << lower);
if (i <= n) {
sum += i;
}
if (i >= n) break outer;
}
}
Let's say we know the closest number, x, equal to or lower than N with 2 set bits, then we can use the formula for power series to quickly sum all positions of the two set bits, for example, if x = b11000, we sum
4*2^0 + S(4)
+ 3*2^1 + S(4) - S(1)
+ 2*2^2 + S(4) - S(2)
+ x
where S(n) = 2 * (1 - 2^n) / (1 - 2) 
= 2 + 2^2 + 2^3 ... + 2^n
With numbers encoded 2 out of 5, exactly two bits are set in every one-digit number. The sum is 45, with the exception of N×(N-1)/2 for 0≤N<9.
I think the question is supposed to discover the pattern.
Fast forward. Given a number N, you can tell the largest number
should count by bitmask from the first two bits are set. So you have
a smaller number M
Skip to next counted number Given any number with two bit set, next
largest number is the shift the second bit by one, until underflow.
Skip to next order When underflow happens on set two, shift the
highest bit by one and also the bit on it's right.
You don't really need a loop on N, but the bits it have.
Next question: can you answer a large number? which N >100,000,000
Next Next question: can you answer the same question for X bits when X>2

Categories

Resources