Why java.Math.BigInteger bugs out after a certain limit? - java

Am trying to print the sum of digits in 2^n for n = 1 to 1000.
Here's what I've done.
public static void main(String[] args) {
int n = 1000;
for (int i = 1; i < n; i++) {
BigInteger power = BigInteger.valueOf((int)Math.pow(2, i));
int sum = 0;
while (power.intValue() > 0) {
sum += power.intValue() % 10;
power = power.divide(BigInteger.valueOf(10));
}
System.out.print(sum + " ");
}
}
It works only till about 2^30 or so and then prints the same result, 46, for the rest.
I tried a similar thing using "long long" in C and that printed 0's after a similar limit.
According to the answers, I changed
BigInteger power = BigInteger.valueOf((int)Math.pow(2, i));
to
BigInteger power = BigInteger.valueOf(2).pow(i);
and 46 changed to 0. Just like C.
Still not working...

You're using Math.pow to generate the value you should use the BigInteger functions to do so instead.
The sum should be stored in a BigInteger as well not an int.

You are doing integer arithmetic and then putting it into a biginteger. Use a biginteger's pow method instead.

Because you aren't using BigInteger.
Computing numbers using BigInteger doesn't let you magically store their sum in an int.
Similarly, passing an int to BigInteger.valueOf() doesn't magically make that int bigger.

You're calling Math.pow() with regular integers, not BigIntegers. You're calling it on integer literals.
You want this:
int i = 7; //or whatever power
BigInteger k = BigInteger.valueOf(2);
k = k.pow(i);

Related

saving many intgers into 1 integer

I am trying to save many natural numbers that are smaller than m into 1 natural number n.
I need a function to read i'th number from n.
In python I can do it like:
def read(n,m,i):#reads a number on index i from n.
return n//m**i%m
def save(numbers_to_save, m=None):#saves natural numbers, that are smaller than m to n.
if m is None:
m=max(numbers_to_save)+1
n=0
for i_number in range(len(numbers_to_save)):
n+=m**i_number*numbers_to_save[i_number]
return n
numbers_to_save=[12,54,3,7,23,8,9,3,72,3]
i_max=len(numbers_to_save)
m=max(numbers_to_save)+1
n=save(numbers_to_save,m)
del numbers_to_save
for i in range(i_max):
print(read(n,m,i),end=",")
But how to do it effectively in java reading n only byte per byte? n is bigger than maximum value of long, so I can not use long to save n.
To translate this code to Java, you would need to use BigInteger class.
It works similarly to Python's "infinite" size integers, but with two key differences:
It is immutable, which means every time you change it, the result is a new object you must store in place of the old one.
You can't use regular operators (+, -, *, +) on it directly, but instead you must use the instance methods such as add or pow.
Here is an example of how your read function will look in Java:
int read(BigInteger n, BigInteger m, int i) {
return n.divide(m.pow(i)).mod(m).intValue();
}
Note, that for simplicity, this code assumes that both i and m will be smaller than MAX_INT.
It is possible to make both of them BigInteger as well to allow them to be of any size.
A long can be used for that specific given numbers (since m**count < Long.MAX_VALUE).
import static java.lang.Math.*;
public static long save(int m, int... numbers) {
long result = 0;
long mult = 1;
for (var num : numbers) {
if (num <0 || num >= m) throw new IllegalArgumentException("invalid: " + num);
result = addExact(result, multiplyExact(mult, num));
mult = multiplyExact(mult, m);
}
return result;
}
public static int read(long compressed, int m, int i) {
return (int) (compressed / (long)pow(m, i) % m);
}
private static void test() {
int[] numbers = { 12, 54, 3, 7, 23, 8, 9, 3, 72, 3};
int m = Arrays.stream(numbers).max().orElseThrow() + 1;
long compressed = save(m, numbers);
for (var i = 0; i < numbers.length; i++) {
int val = read(compressed, m, i);
if (val == numbers[i])
System.out.println(val);
else
System.err.printf("%d != %d # %d%n", val, numbers[i], i);
}
}
I am a bit lazy, so I used the Math methods addExactly and multiplyExact that throw an Exception in case of overflow. Alternative: check if long can save that count of numbers given m at start of method and use
result += mult * num;
mult *= m;
instead in the loop.
Use BigInteger as posted in this answer), if more space is needed.
this code also works with int to compress less, smaller values

Java Compute C(n,k) and factorial with biginteger

I want to compute the answer of C(n,k),such as C(10,2)=10*9/2*1 = 45
If I test my code by small numbers like 10, the code works.
However, when I try to compute C(1000,900), it compiles
Exception in thread "main" java.lang.ArithmeticException: / by zero
I've seen someone says it should use BigInteger,But after I tried, it still has errors.
For example: I change int factorial into BigInteger factorial,
while the for loop in cSelect, I can not change int i into BigInteger type,
As result, the answer up/factorial(y) has errors.
Please help me to fix this problem. Thanks!!
public class Test {
// Write a factorial function
static int factorial(int m) {
int result =1;
for (int i=2; i<=m; i++) {
result = result*i;
}
return result;
}
// Caculate C(x,y)
static int cSelect(int x, int y) {
int up=1;
for(int i=x; i>=(x-y+1); i--) {
up = up*i;
}
return up/factorial(y);
}
public static void main(String[] args) {
System.out.println(cSelect(1000,900));
}
}
Your code is fairly easy to translate in factorial. Start with ONE, multiply by the BigInteger.valueOf(long) for each i in your loop. Like,
// Write a factorial function
static BigInteger factorial(int m) {
BigInteger result = BigInteger.ONE;
for (int i = 2; i <= m; i++) {
result = result.multiply(BigInteger.valueOf(i));
}
return result;
}
Your other function does exactly the same, plus a division by the result of factorial(y). Like,
// Caculate C(x,y)
static BigInteger cSelect(int x, int y) {
BigInteger up = BigInteger.ONE;
for (int i = x; i >= (x - y + 1); i--) {
up = up.multiply(BigInteger.valueOf(i));
}
return up.divide(factorial(y));
}
With no other changes I get
63850511926305130236698511142022274281262900693853331776286816221524376994750901948920974351797699894319420811933446197797592213357065053890
Which I assume is correct.
First, return value must be BigInteger, because result of C(1000,900) far exceeds the range on an int.
Second, you don't need separate factorial() method. Doing the division as you iterate will improve memory footprint by not creating excessively large intermediate values (at cost of doing multiple divisions, but even so it might actually be faster).
Like this:
static BigInteger cSelect(int x, int y) {
BigInteger v = BigInteger.ONE;
for (int i = x, j = 1; j <= y; i--, j++)
v = v.multiply(BigInteger.valueOf(i)).divide(BigInteger.valueOf(j));
return v;
}
By counting i down and j up, there will never be a fraction from the division.
Test
System.out.println(cSelect(10, 2));
System.out.println(cSelect(1000, 900));
Output
45
63850511926305130236698511142022274281262900693853331776286816221524376994750901948920974351797699894319420811933446197797592213357065053890
You have to use BigInteger to do the calculation.
The value you are trying to compute is approximately 6.385051192630516e+139 and it is not representable as a Java primitive integer value.
Even if the result was representable, the reason you are getting divide by zero errors is that the divisor expression 900! ∗ 100! is overflowing to zero. You then divide by that zero.
The reason that it overflows to zero is that it is divisible by 2^32 and 2^64. That can be proven by using some simple algebra to compute the number of factors of 2 there are in 900! and 100!

How to calculate and display large numbers in java

How could I calculate and display all digits of large numbers like 9999! (factorial of 9999) in java?
Take a look at this url which calculates 9999! and dislays all digits.
Use BigInteger, his limit is your memory
public static BigInteger factorial(BigInteger num) {
if (num.compareTo(new BigInteger("1")) < 0) {
return new BigInteger("1");
} else {
return factorial(num.subtract(new BigInteger("1"))).multiply(num) ;
}
}
Use BigInteger; 9999! took 120 ms with Java 8. Here is a version that uses longs, and halves that time:
public static BigInteger factorial(int n) {
// Try first to use longs in calculating the factorial.
BigInteger result = BigInteger.ONE;
long factor = 1;
for (int i = n; i > 1; --i) {
if Long.MAX_VALUE / factor < i) { // Overflow?
result = result.multiply(BigInteger.valueOf(factor));
factor = i;
} else {
factor *= i;
}
}
return result.multiply(BigInteger.valueOf(factor));
}
The Java standard library provide a BigInteger class, which can represent unlimited integer values (actually, they are limited, but only by available memory).
Not the fastest, but not really slow either.
public static BigInteger factorial(int n) {
BigInteger result = BigInteger.ONE;
for (int i = 2; i <= n; i++) {
result = result.multiply(BigInteger.valueOf(i));
}
return result;
}
You can use Strings (yes don't get astonished, you can!). A program can be created in strings to multiply two very large numbers (here i am talking about numbers say 5000 digits in length, each!)
I have already created them for addition and subtraction and it's not that hard to create it for Multiplication and i assure you that, though you will think that using BigInteger will be faster, but using Strings would be Ultrafast as compared to BigInt.
And the thing that slipped my mid, i used StringBuilder class to make the program more efficient.

Different results in Java and Python when computing powers

I am trying to teach myself Java by working through the problems on projecteuler.net, as I have done previously with Python. When attempting problem 16, I replicated the method I used previously in Python. However the result output was different in the two languages. I think it is something to do with Java data types being different from Python. The problem is to sum the digits in the number 2^1000.
In Python:
def sumdigits(n):
s = 0
while n > 0:
s = s + (n % 10)
n = n / 10
return s
print sumdigits(pow(2,1000))
In Java:
public static double SumDigits(double n){
double s = 0;
while (n > 0){
s = s + (n % 10);
n = n / 10;}
return s;
}
System.out.println(SumDigits(Math.pow(2,1000)));
Python produced the correct result and Java produced 1197.1463275484991
Why would these be different?
In Java, double cannot accurately represent 2^1000. As a floating-point number, Math.pow(2,1000) is 1.0715086071862673E301.
To get the result that you want, use BigInteger which preserves the actual value of 2^1000.
public static BigInteger sumDigits(BigInteger n) {
BigInteger num = n;
BigInteger sum = BigInteger.ZERO;
BigInteger ten = BigInteger.valueOf(10);
while (num.compareTo(BigInteger.ZERO) > 0) {
sum = sum.add(num.mod(ten));
num = num.divide(ten);
}
return sum;
}
public static void main(String[] args) {
System.out.println(sumDigits(BigInteger.valueOf(2).pow(1000)));
}
The output of the above code is 1366.
The basic number types in Java are int and double. Both cannot handle a number with 1000 bits. Python has a arbitrary large integer type builtin. For Java you have to find another solution.
In languages with arbitrary large integer arithmetics this problem is trivial
print sum(int(x) for x in str(2**1000))
If you don't have this tool, you have to code multiplication by two on your own.

Java: avoiding factorial overflow

I'm supposed to optimize the following code so that it calculates the central binomial coefficient up to the max value of integer (up to n = 16).
public static int factorial(int n)
{
int result= 1;
for(int i = 2; i <= n; i++) result *= i;
return result;
}
public static int centralbinom(int n)
{
return factorial(2*n) / (factorial(n) * factorial(n));
}
Naturally I get an overflow for every n > 6.
How do I 'break down' the factorial function so that doesn't has to deal with big numbers such as 2n = 2*16 = 32 ?
Or is there a better way to calculate the central binomial coefficient?
Here are several optimizations that you can do in addition to using BigIntegers that may reduce your calculations, in most of you cases overflow that you may be having in your program.
Since you need factorial(n) at least two time. Calculate it once and store it in a variable.
Factorial(2*n) has factorial(n) in it. Since you have already calculated factorial(n) before all you need to do is calculate till factorial(2n....n) and then multiply factorial(n) to it. Here's one way how that can be done.
//Pseudocode
//find factorial of n given I know already till k
int findFactorial(n, k) {
int result = 1
for i n to 1
if(i==k)
break;
result = result * n;
return result
}
//factorial(2*n) = facorial(n, k) * factorial(k)
This will reduce your calculations a lot and in case if you expect your program not to have an overflow, you can go away with BigIntegers.
If you need a factorial of big number, you have to use BigInteger class to calculate result:
public static BigInteger factorial(int n) {
BigInteger result = BigInteger.ONE;
for (int i = 2; i <= n; ++i) {
result = result.multiply(BigInteger.valueOf(i));
}
return result;
}
If the central binomial coefficient of 17 is greater than the integer max, and you only need to compute it for 17 numbers, then the obvious solution is a lookup table. Create a 17-element array containing the central binomial coefficient for n = 0 to 16. I think you'll find this solution is extremely efficient.
You can find a list of them here. http://oeis.org/A000984
Just compress your factorial by gamma.
set gamma to 10 is good enough
public static double factorial(int n, double gamma)
{
double result= 1;
double gammaInv = 1.0/gamma;
for(int i = 2; i <= n; i++) result *= pow(i,gammaInv);
return result;
}
public static int centralbinom(int n, double gamma)
{
return pow(factorial(2*n,gamma) /
(factorial(n,gamma) * factorial(n),gamma),
gamma);
}

Categories

Resources