How to avoid java.lang.OutOfMemoryError? - java

I have two simple java codes.The first one defines constant power as power = a.pow(b);
import java.math.BigInteger;
public class FermatOne
{
public static void main(String[] args)
{
BigInteger a = new BigInteger ("2");
BigInteger k = new BigInteger ("15");
BigInteger c = new BigInteger ("1");
int b = 332192810;
BigInteger n = new BigInteger ("2");
BigInteger power;
power = a.pow(b);
BigInteger exponent;
exponent = k.multiply(power);
BigInteger mod;
mod = exponent.add(c);
BigInteger result = n.modPow(exponent,mod);
System.out.println("Result is ==> " + result);
}
}
The second one defines constant power as power = BigInteger.ONE.shiftLeft(b)
import java.math.BigInteger;
public class FermatOne
{
public static void main(String[] args)
{
BigInteger k = new BigInteger ("15");
BigInteger c = new BigInteger ("1");
int b = 332192810;
BigInteger n = new BigInteger ("2");
BigInteger power;
power = BigInteger.ONE.shiftLeft(b);
BigInteger exponent;
exponent = k.multiply(power);
BigInteger mod;
mod = exponent.add(c);
BigInteger result = n.modPow(exponent,mod);
System.out.println("Result is ==> " + result);
}
}
Setting the memory flag -Xmx1024m in the command line the first code works fine , but for the second code I am getting error : java.lang.OutOfMemoryError :Java heap space
My question : What should I change in the second code to avoid java.lang.OutOfMemoryError ?

You're trying to calculate a number like 2 ^ (15 * 2 ^ 332192809). I don't know if you could even fit such a number in the universe!! Or maybe, the answer is simply... 42 ? ;-)
On a more serious note, you'll really have trouble, calculating this number. Encoded in bits, 15 * 2 ^ 332192810 would require almost a gigabyte by itself. Then raising 2 to that power again, I don't want to know...
On a more serious note, when you dig into the implementation of java.math.BigInteger, I think that you just run into such an error faster with the left shift, as that is implemented much more efficiently, than the power method. Having said this, have you tried to force garbage collection in your code, using System.gc()?
UPDATE: My original reasoning might've been wrong. 2 ^ 332192809 can be calculated with 1GB. And the overall result might be "modded" efficiently by java.math.BigInteger, although I believe that this calculation might take a while...

It's just a guess, but BigInteger.ONE.shiftLeft(332192810); will internally create an int array of length x + 10381025. Since an int is 4 bytes big you'll get about 40 mega bytes of data just for that one call. I assume the other calls copy that data around and thus you get that high a memory consumption.

Related

how to find number of digits in factorial of 42?

factorial of 42 is going beyond the final limit of long data type in java. that's why I can't find digits.
42!
The factorial of 42 is of 51 digits while the max limit of long datatype in Java is 9,223,372,036,854,775,807 i.e only 20 digits. But don't worry, Java has a Big Integer class to store large numbers such as 100!. But it's a bit slower than primitive data types such as int, long etc because it stores integers in the form of arrays. There are many ways to implement the Big Integer class but here's the most used way. This code calculates the factorial of 42 and prints the same-
// Java program to find large factorials using BigInteger
import java.math.BigInteger;
public class Factorial
{
// Returns Factorial of N
static BigInteger factorial(int N)
{
BigInteger fact = new BigInteger("1"); // Or BigInteger.ONE
// Multiply f with 2, 3, ...N
for (int i = 2; i <= N; i++)
fact = fact.multiply(BigInteger.valueOf(i));
return fact;
}
public static void main(String args[])
{
int N = 42;
System.out.println(factorial(N));
}
}
Output:
1405006117752879898543142606244511569936384000000000
Explanation
We have to import the Big Integer class, which is stored in java.math package. I have named my file Factorial.java, so my class name is Factorial.
In this method, I've created a function, if you want the code without function, just comment below. Now in this syntax-
BigInteger f = new BigInteger("1");
I've assigned fact as Big integer which is equal to 1. In the for loop,
i value is set to 2 s 1*1=1.
fact = fact.multiply(BigInteger.valueOf(i));
The above syntax is for the multiplication of Big integers. This multiplies the Biginteger fact by i.
Have a look at this GeeksforGeeks article- https://www.geeksforgeeks.org/biginteger-class-in-java/
If you only care about the number of digits, I would recommend taking a more mathematical approach. There are ways to compute this number without actually computing the factorial itself. This would not require so big a variable and would be a lot faster.
You could think it this way:
Digits(n!) = floor(log10(n!)) + 1 = floor(log10(n * (n - 1) * ... * 1)) + 1 =floor(\sum_{i = 1}^{n}log10(i)) + 1
A picture of this expression: expression
This would still require iteration, but it deals with much smaller numbers.
If you still want O(1) complexity for this task, you can go with a pretty good approximation I've just tried.
Digits(n!) ~ floor(\int_{1}^{x}log10(x) dx) + 1 = floor(\frac{-x + x*ln(x) + 1}{ln(10)}) + 1
Another image of this formula: approximate expression
Of course, the latter is no absolutely exact since we are now integrating a continuous function. However, it will probably be worth implementing.
Digits(42!) = floor(50.37...) + 1 = 50 + 1 = 51

How to return int if BigInteger is too big for int?

i'm currently trying to solve a HackerRank problem, the problem in question is called Fibonacci Modified.
The method returns an int but it is expected that I will be obtaining huge values. I'm solving this problem in Java.
Here is my code
static int fibonacciModified(int t1, int t2, int n) {
BigInteger[] f = new BigInteger[n];
f[0] = BigInteger.ZERO;
f[1] = BigInteger.ONE;
BigInteger value = BigInteger.ONE;
for(int i = 2; i < n; i++) {
f[i] = f[i-1].multiply(f[i-1]).add(f[i-2]);
value = f[i];
}
return value.intValue();
}
I'm failing the test case when t1 = 0, t2 = 1, n = 10. My output is -1022889632.
The correct answer is 84266613096281243382112. If I change the method to return a BigInteger then I do get the right answer.
Edit: This is the link to the problem https://www.hackerrank.com/challenges/fibonacci-modified/problem
You cannot, the maximum value for int is 2,147,483,647 (32 bits of value). If you need big numbers you must use the appropriate variable type.
If for some reason you want to avoid BigInteger at all and your are not going to do any arithmetic operation later, you can always return a String
About the hackerrank problem, just modify the result variable type to BigInteger. Actually, they seem to be aware of the 32/64 bits issue... they are using a String value to prevent it.
There's no reason to keep the whole code-template structure. They just care about input/output. You are allowed to modify EVERYTHING but those two things.
This is their input:
This is their output (here you can see their output is expected to be a String):

Square Root and ++ Operators for BigInteger and BigDecimal

Is there any ready-made Java library for operations over BigInteger and BigDecimal objects?
I'd like to use square root and ++ operators.
Thank you
P.S. BigInteger.add() should be used instead of ++, I got it.
What about square root from BigInteger?
BigInteger is immutable. That makes something like the ++-operator on it conceptually impossible. You can not change the value of a given BigInteger, just like you can't do it with String.
Incrementing
You always have to create a new BigInteger that holds the incremented value (you can then of course store the reference to that BigInteger in the same variable).
Edit: As pointed out in the comment, "incrementing" would look like:
BigInteger result = a.add(BigInteger.ONE);
or
a = a.add(BigInteger.ONE);
Note that both lines do not change the value of the BigInteger which a originally points to. The last line creates a new BigInteger and stores the reference to it in a.
Calculating the Square
You can calculate the square of a BigInteger like this:
BigInteger a = BigInteger.valueOf(2);
BigInteger a_square = a.multiply(a); // a^2 == a * a
or
BigInteger a_square = a.pow(2);
Square Root
The code is taken from https://gist.github.com/JochemKuijpers/cd1ad9ec23d6d90959c549de5892d6cb .
It uses simple bisection and a clever upper bound. Note that a.shiftRight(x) is equivalent to a / 2^x (only for non-negative numbers, but that is all we deal with, anyway)
BigInteger sqrt(BigInteger n) {
BigInteger a = BigInteger.ONE;
BigInteger b = n.shiftRight(5).add(BigInteger.valueOf(8));
while (b.compareTo(a) >= 0) {
BigInteger mid = a.add(b).shiftRight(1);
if (mid.multiply(mid).compareTo(n) > 0) {
b = mid.subtract(BigInteger.ONE);
} else {
a = mid.add(BigInteger.ONE);
}
}
return a.subtract(BigInteger.ONE);
}
Using Operators Instead of Methods
Operator overloading like in C++ is not possible in Java.

BigInteger power of a BigDecimal in Java

I tried to get the power of a double value where the exponent is very large (Java BigInteger can contain it (the exponent), for example: 10^30)
That is, I want to find something like 1.75^(10^30) or 1.23^(34234534534222).if the output is too large modify it by getting the modulus by a prime like 10^9+7.
If I want to find a power of an Integer I can use BigInteger.modPow() method which take BigInteger arguments:
( BigInteger modPow(BigInteger exponent, BigInteger m) )
As far as i can go this is what i got in Java
new BigDecimal("1.5").pow(1000); // .pow() can get only integers as a parameter , but i want to pass a big number like a BigInteger
I cannot find an equivalent for that (BigInteger.modPow()) in java for BigDecimal
, or i'm missing that.
Are there any ways to do that - Calculate a large power of a floating point number (a Decimal)?
Example of input and output :
Input : num // or 1.5 or any decimal number. can be an integer also.
exponent : exp // big integer or a Long value
output : num^exp // num to ther power exp
i.e like calculating 1.23^(34234534534222)
if the output is too large modify it by getting the modulus by a prime like 10^9+7
There is a Math.BigDecimal implementation of core mathematical functions which has:
static java.math.BigDecimal powRound(java.math.BigDecimal x, java.math.BigInteger n)
Raise to an integer power and round.
which seems exactly what you need. The fact that there is an external library for it denotes that there is no core implementation of a method like this in java.Math.
As a side note I can say that if your input is considerably small in terms of decimal places (thus no irrational) just like 1.5 you can transform it in 15/10 and do
(15^BigInteger)/(10^BigInteger)
with the modPow(BigInteger exponent, BigInteger m) of BigInteger. This obviously raises the complexity and the numbers to calculate.
There are several caveats. As Gábor Bakos pointed out, the resulting value would most likely contain too many digits to even be represented as a BigDecimal.
Additionally, these number of digits grows quickly, so computing something like 2.034234534534222 is completely out of scope in terms of storage (and, as I assume, in terms of required time).
You mentioned that the value may be computed modulo a large prime when it becomes "too large". Although you did not say what exactly this means, this won't necessarily help you here, because using modulo will not truncate the decimal places. You'll somehow have to limit the precision in which the computation takes place.
However, the most simple implementation using exponentiation by squaring could roughly look like this:
import java.math.BigDecimal;
import java.math.BigInteger;
public class BigDecimalPow {
public static void main(String[] args) {
BigDecimal b = new BigDecimal(1.5);
BigInteger e = new BigInteger("325322");
BigDecimal result = pow(b, e);
System.out.println("Done "+result.scale());
System.out.println(result);
}
/**
* Computes d to the power of e
* #param b The value
* #param e The exponent
* #return The power
*/
private static BigDecimal pow(BigDecimal b, BigInteger e) {
BigDecimal result = BigDecimal.ONE;
BigDecimal p = b;
int skipped = 0;
while (e.compareTo(BigInteger.ZERO) > 0) {
if (e.and(BigInteger.ONE).equals(BigInteger.ONE)) {
if (skipped > 0) {
if (skipped > 29) {
p = pow(p, BigInteger.ONE.shiftLeft(skipped));
} else {
p = p.pow(1 << skipped);
}
skipped = 0;
}
result = result.multiply(p);
}
skipped++;
e = e.shiftRight(1);
System.out.println(e);
}
return result;
}
}
Note: The implementation above is really simple. There most likely is a solution that is more efficient for some cases, or uses the modulo operation to support "larger" numbers. But you simply can not represent (potentially) 34234534534222 decimal places unless you have 34 terabytes of RAM and a JVM with long addressing, so I doubt that there will be a solution that satisfies the requirements that you stated until now - but would upvote+bounty anyone who proved me wrong...

Get the maximum value for a BigInteger with n bits

I want to compare two multiplication methods implemented in Java which use shift operations on big numbers. Thus I need sufficiently large BigIntegers.
Since I want to compare them bit-wise, what would be the best approach to generate BigIntegers with n bits which are fully used in the multiplication operation.
My approach so far is this:
byte[] bits = new byte[bitLength];
BigInteger number = new BigInteger(bits).flipBit(bitLength);
How about this:
import java.math.BigInteger;
public class Test
{
public static void main(String[] args)
{
int bits = 3;
BigInteger value = BigInteger.ZERO
.setBit(bits)
.subtract(BigInteger.ONE);
System.out.println(value); // Prints 7 == 111 in binary
}
}
In other words, set the bit which is one higher than you want, then subtract one to get a value which uses all the lower bits.

Categories

Resources