Calculating factorials with numbers bigger than ints and longs in java? - java

Been searching here and google for a couple of days as well as asking my programming friends.
Unfortunately, i still don't understand how to change my code...
My program calculates the factorial of a given number. It then provides a number which represents how many digits the factorials answer includes. Then it sums the values of those digits together to give a total.
My program works for any number between 1! and 31!... If you put in anything over 31! (for example 50! or 100!) it doesn't work and just throws back minus numbers and no total.
I was hoping you guys could point me in the right direction or give me some advice.
I understand using BigIntegers maybe a solution however i don't understand them personally, hence coming here.
Any help would be much appreciated. Thanks.
package java20;
/**
* Program to calculate the factorial of a given number.
* Once implemented, it will calculate how many digits the answer includes.
* It will then sum these digits together to provide a total.
* #author shardy
* date: 30/09/2012
*/
//import java.math.BigInteger;
public class Java20 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
//Using given number stored in factorialNo, calculates factorial
//currently only works for numbers between 1! and 31! :(
int fact= 1;
int factorialNo = 10;
for (int i = 1; i <= factorialNo; i++)
{
fact=fact*i;
}
System.out.println("The factorial of " + factorialNo +
" (or " + factorialNo + "!) is: " + fact);
//Using answer stored in fact, calculates how many digits the answer has
final int answerNo = fact;
final int digits = 1 + (int)Math.floor(Math.log10(answerNo));
System.out.println("The number of digits in the factorials "
+ "answer is: " + digits);
//Using remainders, calculates each digits value and sums them together
int number = fact;
int reminder;
int sum = 0;
while(number>=1)
{
reminder=number%10;
sum=sum+reminder;
number=number/10;
}
System.out.println("The total sum of all the " + digits
+ " idividual digits from the answer of the factorial of "
+ factorialNo + " is: " + sum);
}
}

You can use BigInteger in java, it has as much numbers as you want
BigInteger fact= BigInteger.ONE;
int factorialNo = 10;
for (int i = 2; i <= factorialNo; i++){
fact = fact.multiply(new BigInteger(String.valueOf(i)));
}
System.out.println("The factorial of " + factorialNo +
" (or " + factorialNo + "!) is: " + fact);
final int digits = fact.toString().length();
BigInteger number = new BigInteger(fact.toString());
BigInteger reminder;
BigInteger sum = BigInteger.ZERO;
BigInteger ten = new BigInteger(String.valueOf(10));
while(number.compareTo(BigInteger.ONE)>=0)
{
reminder=number.mod(ten);
sum=sum.add(reminder);
number=number.divide(ten);
}
System.out.println("The total sum of all the " + digits
+ " idividual digits from the answer of the factorial of "
+ factorialNo + " is: " + sum
EDIT: the code is improved to be compatible with author's code

If you put in anything over 31! (for example 50! or 100!) it doesn't
work and just throws back minus numbers and no total.
This is because primitive integer types are subject to overflow when you exceed their maximum possible value. Which computing factorials has a tendency to do.
I was hoping you guys could point me in the right direction or give me
some advice. I understand using BigIntegers maybe a solution however i
don't understand them personally, hence coming here.
You are correct that using BigInteger is one possible solution. You can, for instance, do something like:
public BigInteger factorial(int num) {
if (num < 0) {
throw new IllegalArgumentException("Not today!");
}
BigInteger result = BigInteger.ONE;
for (int next = 2; next <= num; next++) {
result = result.multiply(new BigInteger(Integer.toString(next, 10)));
}
return result;
}

If you're calculating things like (m!/n!), you are better off using logarithms of factorials.
You should also consider these two improvements:
Memoize, don't recalculate. Store those hard-earned values once you calculate them.
You should be using the gamma function to calculate factorials. The way you're doing it with a loop is the naive thing that is presented to students. There's a nice implementation of ln(gamma(x)) in Numerical Recipes.
You can always use BigDecimal if you must, but it's a last resort. You should still consider these points.
There's a gamma function implementation available from Apache Commons. The source code might not be as familiar as the naive approach, but if you see how it's done it'll be obvious that it's more efficient even for moderate arguments.

Related

Did I just increase the complexity of reversing a number? [duplicate]

This question already has answers here:
Java Math.pow(a,b) time complexity
(2 answers)
Closed 4 years ago.
public class HelloWorld{
public static void main(String []args){
int orig=103, reverse=0, mod;
int numOfDigits=0;
int n = orig;
while (n>0){
n /= 10;
numOfDigits++;
}
n = orig;
while (n > 0){
mod = n % 10;
reverse = reverse + (int)(mod * java.lang.Math.pow(10, numOfDigits-1));
numOfDigits--;
n /= 10;
}
System.out.println("Reversed is : " + reverse);
}
}
I do know that reverse = reverse + (int)(mod * java.lang.Math.pow(10, numOfDigits-1)); can be replaced by reverse = mod + (reverse*10).
Was wondering if I had just increased the complexity of a simple program by calculating total number of digits and applying power?
P.S: Kindly assume that orig can be taken as an input from the user and could be a number of any number of digits. I have hard coded only for experiment.
You didn't increase the complexity ... but you did make it slower. The expression pow(10, numOfDigits - 1) will be substantially slower than reverse = mod + (reverse * 10)
It is also possible that a computation that uses Math.pow instead of integer multiplication is inaccurate due to floating point imprecision. A double has only 52 bits of precision, compared with 63 for a long. In this example, this probably doesn't apply, but it is something to be wary of, in general
Probably, this would be the best approach with less iteration & complexity:
public class NumReverse {
public long reverseNumber(long number){
long reverse = 0;
while(number != 0){
reverse = (reverse*10)+(number%10);
number = number/10;
}
return reverse;
}
public static void main(String a[]){
System.out.println("Reversed is: "+new NumReverse().reverseNumber(103));
}
}
compute the multiply times and add times:
suppose f(x) = an * x^n + an-1 * x^n-1 + ... + a1 * x + a0
1. If calculate f(x) by computing one item by one item,
it will take (n+1) + n + (n-1) + ... + 1 + 0 = (n+1)(n+2)/2 multiply times and n addition times.
2. If calculate f(x) by n = n*10 + mod,
it will take n multiply times and n addition times.
Of course, if pow() has some optimization such as "divide and conquer", the complexity of pow() should be O(logN).

I need to print the 215th Lucas Numbers using an efficient algorithm. Using recursion takes way too long.

The purpose of this class is to calculate the nth number of the Lucas Sequence. I am using data type long because the problems wants me to print the 215th number. The result of the 215th number in the Lucas Sequence is: 855741617674166096212819925691459689505708239. The problem I am getting is that at some points, the result is negative. I do not understand why I am getting a negative number when the calculation is always adding positive numbers. I also have two methods, since the question was to create an efficient algorithm. One of the methods uses recursion but the efficiency is O(2^n) and that is of no use to me when trying to get the 215th number. The other method is using a for loop, which the efficiency is significantly better. If someone can please help me find where the error is, I am not sure if it has anything to do with the data type or if it is something else.
Note: When trying to get the 91st number I get a negative number and when trying to get the 215th number I also get a negative number.
import java.util.Scanner;
public class Problem_3
{
static long lucasNum;
static long firstBefore;
static long secondBefore;
static void findLucasNumber(long n)
{
if(n == 0)
{
lucasNum = 2;
}
if(n == 1)
{
lucasNum = 1;
}
if(n > 1)
{
firstBefore = 1;
secondBefore = 2;
for(int i = 1; i < n; i++)
{
lucasNum = firstBefore + secondBefore;
secondBefore = firstBefore;
firstBefore = lucasNum;
}
}
}
static long recursiveLucasNumber(int n)
{
if(n == 0)
{
return 2;
}
if(n == 1)
{
return 1;
}
return recursiveLucasNumber(n - 1) + recursiveLucasNumber(n - 2);
}
public static void main(String[] args)
{
System.out.println("Which number would you like to know from "
+ "the Lucas Sequence?");
Scanner scan = new Scanner(System.in);
long num = scan.nextInt();
findLucasNumber(num);
System.out.println(lucasNum);
//System.out.println(recursiveLucasNumber(num));
}
}
Two observations:
The answer you are expecting (855741617674166096212819925691459689505708239) is way larger than you can represent using a long. So (obviously) if you attempt to calculate it using long arithmetic you are going to get integer overflow ... and a garbage answer.
Note: this observation applies for any algorithm in which you use a Java integer primitive value to represent the Lucas numbers. You would run into the same errors with recursion ... eventually.
Solution: use BigInteger.
You have implemented iterative and pure recursion approaches. There is a third approach: recursion with memoization. If you apply memorization correctly to the recursive solution, you can calculate LN in O(N) arithmetical operations.
Java data type long can contain only 64-bit numbers in range -9223372036854775808 .. 9223372036854775807. Negative numbers arise due to overflow.
Seems you need BigInteger class for arbitrary-precision integer numbers
I wasn't aware of the lucas numbers before this thread, but from wikipedia it looks like they are related to the fibonacci sequence with (n = nth number, F = fibonacci, L = lucas):
Ln = F_(n-1) + F_(n+1)
Thus, if your algorithm is too slow, you could use the closed form fibonacci and than compute the lucas number from it, alternative you could also use the closed form given in the wikipedia article directly (see https://en.wikipedia.org/wiki/Lucas_number).
Example code:
public static void main(String[] args) {
long n = 4;
double fibo = computeFibo(n);
double fiboAfter = computeFibo(n + 1);
double fiboBefore = computeFibo(n - 1);
System.out.println("fibonacci n:" + Math.round(fibo));
System.out.println("fibonacci: n+1:" + Math.round(fiboAfter));
System.out.println("fibonacci: n-1:" + Math.round(fiboBefore));
System.out.println("lucas:" + (Math.round(fiboAfter) + Math.round(fiboBefore)));
}
private static double computeFibo(long n) {
double phi = (1 + Math.sqrt(5)) / 2.0;
double psi = -1.0 / phi;
return (Math.pow(phi, n) - Math.pow(psi, n)) / Math.sqrt(5);
}
To work around the long size limit you could use java BigDecimal (https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html). This is needed earlier in this approach as the powers in the formula will grow very quickly.

Issue with Java simple arithmetic

I'm working on a small Java program, and somewhere, my calculations are going awry. My code is as follows:
import java.io.*;
import java.util.*;
import java.text.*;
public class NumManip
{
public static void main(String args[])
{
Scanner numGetter = new Scanner(System.in);
final int MULT_1 = 9;
final int MULT_2 = 12345679;
final int MULT_3 = 1000;
int poorHatedNumber;
System.out.print("Enter a digit between 1 and 9 that you dislike: ");
poorHatedNumber = numGetter.nextInt();
int num1 = poorHatedNumber * MULT_1, num2 = num1 * MULT_2;
long num3 = num2 * MULT_3;
System.out.println();
System.out.println(" " + poorHatedNumber);
System.out.println(" " + "x" + MULT_1);
System.out.println(" __");
System.out.println(" " + num1);
System.out.println(" x" + MULT_2);
System.out.println(" __");
System.out.println(" " + num2);
System.out.println(" x" + MULT_3);
System.out.println("____________");
System.out.println(num3);
}
}
I've tryed printing num1, num2, and num3 on the screen to see what the problem is, and num1 is right, num2 is right, and num3 is freaky. My input is 9, and the first calculation multiplies by 9 and gets 81. Then it multiplies that by 12345679 and gets 999999999, and then it multiplies by 1000 and gets -727380968. What's wrong with that last step? I'm REALLY new to Java, and I don't get the issue.
999999999 * 12345679 = 1.234567898765432e+16 which is way bigger than the maximum value of an int which is 2,147,483,647
Since Java uses 2-compliment method to store int number (meaning that the leftmost bit is turned on when the number is negative) this calculation "overflows" (carry-over) to the that bit which results in a negative result.
For calculation with such big numbers you should use BigDecimal
As num2 and num1 both are integer, so integer multiplication happened and it exceeds the max of integer value.
long num3 = (long)num2 * MULT_3;
I think you're resulting in a number bigger than the datatype can handle, and as the datatype is signed, it wraps around into the negatives.
Don't worry, it's not such a silly mistake really. The whole "numbers are usually a fixed size"-deal confuses just about everyone initially. Now that you know what's up, here's something even weirder. It's not really an answer to your question, but now that you've just seen an example of "bad overflow", you might find this interesting.
Consider an odd number x. There is a number y such that x * y == 1. That number y is called the modular multiplicative inverse, and it can easily be computed (see Hacker's Delight, exact division by a constant). This may seem really counter intuitive, because it essentially allows a weird kind "division" that only works if the number was an exact multiple of the divisor, and in general it allows you to "undo" a multiplication by an odd number. For example, if you have a = 3 * b, then b = -1431655765 * a - regardless of any overflow in either multiplication, so overflow need not be "destructive".

Project Euler #2 Infinity?

I am trying to solve Euler's Project #2 and I keep getting the answer as "Infinity" or "NaN" (Not a number) I tried changing the type of number to a int (originally Double), but that didn't fix anything just gave me the answer "-1833689714"
public class Pro {
static int g = 1;
static int n, f = 0;
public static void main(String args[]) {
for (int i = 0; i <= 4000000; i++) {
f = f + g;
g = f - g;
if (f % 2 == 0) {
n += f;
}
}
System.out.println("Answer: " + n);
}
}
The questions is:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
You are considering the first 4,000,000 terms of the Fibonacci sequence instead of the first x terms which do not exceed 4,000,000.
Your problem is an integer overflow: in Java, an int variable is limited to Integer.MAX_VALUE (2147483647). If you exceed this value in a computation, you overflow to Integer.MIN_VALUE, the smallest negative value. See:
public class IntegerOverflow {
public static void main(String[] args) {
int i = Integer.MAX_VALUE;
System.out.println("i = Integer.MAX_VALUE: " + i);
System.out.println("i + 1: " + (i + 1));
System.out.println("i + 2: " + (i + 2));
}
}
To avoid overflow problems, perform your computation with arbitrary-precision integers, provided by the java.math.BigInteger class:
import java.math.BigInteger;
public class BigIntegerExample {
public static void main(String[] args) {
BigInteger b = BigInteger.valueOf(Long.MAX_VALUE);
System.out.println("b = Long.MAX_VALUE: " + b);
System.out.println("b**2: " + b.multiply(b));
System.out.println("b**3: " + b.pow(3));
System.out.println("b**10: " + b.pow(10));
}
}
Note: As you did not ask for help with the problem itself, I am just answering the question. Hope this helps
You are probably encountering an overflow. fibo(4000000) is way above MAX_INT.
Note: that you are not asked to find the sum even numbers in the 4,000,000 first numbers, but to find the sum of even elements which their value is not over 4,000,000.
You should check if f< 4000000 and if not, break, and not wait to i reach 4,000,000
You are checking the first 4 million fibonacci, you need to only check terms until a fibonnaci term is greater than 4 million then stop. The reason you are getting negative numbers is that you are eventually getting fibonacci terms which are greater than Integer.MAX_INT, at which point you overflow and start getting negative numbers, which you are adding to your total. If you aren't positive whether or not the eventual answer is going to exceed Integer.MAX_INT, you should be using a long as your accumulator instead of an int.
Use GMP to handle big numbers in C.
And a little bit of thinking before does not hurt either (like how often is there an odd number versus even, what is the sum of the first n elements of Fibonacci sequence)...
You can use long instead of int.
Every third expression is even, so you only need to evaluate every third value. This is slighly faster because it loops less times and you don't have to test for even/odd.
You only need to n not the i which is less than 4 million.
This is how I got the answer:
def fib():
x,y = 0,1
while True:
yield x
x,y = y, x+y
def even(seq):
for number in seq:
if not number % 2:
yield number
def under_a_million(seq):
for number in seq:
if number > 4000000:
break
yield number
print sum(even(under_a_million(fib())))
-M1K3

Predicting the number of digits of a multiplication

I need to find the number of digits of very large multiplications (about 300 digits each). I was wondering if there is a trick to predict the number of digits that the product will be without actually performing the calculation.
The number of digits can be calculated exactly by the rounded (down) sum of the base 10 log of the two multiplicands plus 1, as follows:
public static void main(String[] args) {
DecimalFormat f = new DecimalFormat("#");
double num1 = 12345678901234567890d;
double num2 = 314159265358979d;
// Here's the line that does the work:
int numberOfDigits = (int) (Math.log10(num1) + Math.log10(num2)) + 1;
System.out.println(f.format(num1) + " * " + f.format(num2) + " = " +
f.format((num1 * num2)) + ", which has " + numberOfDigits + " digits");
}
Output:
12345678901234567000 * 314159265358979 = 3878509413969699000000000000000000, which has 34 digits
This will work for arbitrarily large numbers.
Cristobalito's answer pretty much gets it. Let me make the "about" more precise:
Suppose the first number has n digits, and the second has m. The lowest they could be is 10^(n-1) and 10^(m-1) respectively. That product would the lowest it could be, and would be 10^(m+n-2), which is m+n-1 digits.
The highest they could be is 10^n - 1 and 10^m - 1 respectively. That product would be the highest it could be, and would be 10^(n+m) - 10^n - 10^m + 1, which has at most m+n digits.
Thus if you are multiplying an n-digit number by an m-digit number, the product will have either m+n-1 or m+n digits.
Similar logic holds for other bases, such as base 2.

Categories