I am to find the last ten digits of 1^1 + 2^2 + 3^3.. + 1000^1000.
Is there any way to find this out with pure logic? I think you can't store a number that big.
This question is from a math competition, but I thought of trying to do this in Java.
You don't need to store number that big, you just need the last ten digits. You can store this in a long.
An efficient way to calculate large powers is to multiply and the squares e.g. 19^19 = 19 * 19^2 * 19 ^ 16 = 19 * 19 ^ 2 * 19^2^2^2^2. When you have value which is greater than 10^10 you can truncate the last 10 digits.
BTW the last ten digits of 1000^1000 is 0000000000 and when your add this to your sum, it's the same as adding zero ;)
Edit: While you don't have to use BigInteger, it is simpler to write.
BigInteger tenDigits = BigInteger.valueOf(10).pow(10);
BigInteger sum = BigInteger.ZERO;
for (int i= 1; i <= 1000; i++) {
BigInteger bi = BigInteger.valueOf(i);
sum = sum.add(bi.modPow(bi, tenDigits));
}
sum = sum.mod(tenDigits);
modPow is more efficient than pow with mod seperately as it doesn't have to calculate very large numbers, only the result of the mod.
You could use BigIntegers...
public static void main(String[] args) {
BigInteger acc = BigInteger.ZERO;
for (int k = 1; k <= 1000; k++) {
BigInteger pow = BigInteger.valueOf(k).pow(k);
acc = acc.add(pow);
}
System.out.println(acc);
}
I believe the problem comes from Project Euler, so it's not just a math problem; it should require some computation as well. I don't know how it could be solved with pencil and paper other than by duplicating the calculations a computer might make. I can't see much in the way of a purely mathematical solution. Mathematics can help us optimize the code, however.
To raise a^n, find the binary expansion of n:
n = n_k x 2^k + n_(k-1) x 2^(k-1) + ... + n_0 x 2^0
where n_i = 0 or 1 are the binary digits of n with the zeroth digit on the right. Then
a^n = a^(n_k x 2^k) x a^(n_(k-1) x 2^(k-1)) x ... x a^(n_0 x 2^0).
We can ignore any factors where n_i = 0, since the factor is then a^0 = 1. The process can be written as an algorithm which is O(log n) time and O(1) space (see below).
Next, as a challenge, in order to avoid the use of BigInteger, we can break the calculation into two parts: finding the answer mod 2^10 and finding the answer mod 5^10. In both cases the numbers in the relevant ranges and products of numbers in the relevant ranges fit into longs. The downside is that we have to use the Chinese Remainder Theorem to recombine the results, but it's not that hard, and it's instructive. The hardest part of using the Chinese Remainder Theorem is finding inverses mod m, but that can be accomplished in a straightforward manner using a modification of the Euclidean algorithm.
Asymptotic running time is O(n log n), space is O(1), and everything fits into a few long variables, no BigInteger or other sophisticated library required.
public class SeriesMod1010 {
public static long pow(long a,long n,long m) { // a^n mod m
long result = 1;
long a2i = a%m; // a^2^i for i = 0, ...
while (n>0) {
if (n%2 == 1) {
result *= a2i;
result %= m;
}
a2i *= a2i;
a2i %= m;
n /= 2;
}
return result;
}
public static long inverse(long a, long m) { // mult. inverse of a mod m
long r = m;
long nr = a;
long t = 0;
long nt = 1;
long tmp;
while (nr != 0) {
long q = r/nr;
tmp = nt; nt = t - q*nt; t = tmp;
tmp = nr; nr = r - q*nr; r = tmp;
}
if (r > 1) return -1; // no inverse
if (t < 0) t += m;
return t;
}
public static void main(String[] args) {
long twoTo10 = 1024;
long sum210 = 0;
for (long i=1; i<=1000; i++) {
sum210 += pow(i,i,twoTo10);
sum210 %= twoTo10;
}
long fiveTo10 = 9_765_625;
long sum510 = 0;
for (long i=1; i<=1000; i++) {
sum510 += pow(i,i,fiveTo10);
sum510 %= fiveTo10;
}
// recombine the numbers with the Chinese remainder theorem
long tenTo10 = 10_000_000_000L;
long answer = sum210 * inverse(fiveTo10,twoTo10) * fiveTo10
+ sum510 * inverse(twoTo10,fiveTo10) * twoTo10;
answer %= tenTo10;
System.out.println(answer);
}
}
use BigIntegers :
import java.math.BigInteger;
public class Program {
public static void main(String[] args) {
BigInteger result = new BigInteger("1");
BigInteger temp = new BigInteger("1");
BigInteger I;
for(int i = 1 ; i < 1001 ; i++){
I = new BigInteger(""+i);
for(int j = 1 ; j < i ; j++){
temp = temp.multiply(I);
}
result = result.multiply(temp);
temp = new BigInteger("1");
}
System.out.println(result);
}
}
It can be solved without BigInteger, because you need to store only 10 last digits on every addition or multiplication operation, using % to avoid overflow:
int n = 1000;
long result = 0;
long tenDigits = 10_000_000_000L;
for (int i = 1; i <= n; i++) {
long r = i;
for (int j = 2; j <= i; j++) {
r = (r * i) % tenDigits;
}
result += r;
}
return result % tenDigits;
Complexity is O(N^2), supposed that multiplication runs in constant time.
Answer: 9110846700.
The decimal base uses 0...9 (10 digits) to represent digits, a number that is in the second position right to left represents Digits * base.length^l2rPosition. Using this logics you can create a class that "pretty much does what your primary school teacher told you to, back when we used paper to calculate stuff, but with a baseN number and base-to-base conversions" I have done this class fully functional in C#, but I don't have time to translate it completely to java, this is about the same logics behind java.math.BigInteger. (with less performance I bet for I used a lot of lists >_>" No time to optimize it now
class IntEx {
ArrayList<Integer> digits = new ArrayList<>();
long baseSize = Integer.MAX_VALUE+1;
boolean negative = false;
public IntEx(int init)
{
set(init);
}
public void set(int number)
{
digits = new ArrayList<>();
int backup = number;
do
{
int index = (int)(backup % baseSize);
digits.add(index);
backup = (int) (backup / baseSize);
} while ((backup) > 0);
}
// ... other operations
private void add(IntEx number)
{
IntEx greater = number.digits.size() > digits.size() ? number : this;
IntEx lesser = number.digits.size() < digits.size() ? number : this;
int leftOvers = 0;
ArrayList<Integer> result = new ArrayList<>();
for (int i = 0; i < greater.digits.size() || leftOvers > 0; i++)
{
int sum;
if (i >= greater.digits.size())
sum = leftOvers;
else if(i >= lesser.digits.size())
sum = leftOvers + greater.digits.get(i);
else
sum = digits.get(i) + number.digits.get(i) + leftOvers;
leftOvers = 0;
if (sum > baseSize-1)
{
while (sum > baseSize-1)
{
sum -= baseSize;
leftOvers += 1;
}
result.add(sum);
}
else
{
result.add(sum);
leftOvers = 0;
}
}
digits = result;
}
private void multiply(IntEx target)
{
ArrayList<IntEx> MultiParts = new ArrayList<>();
for (int i = 0; i < digits.size(); i++)
{
IntEx thisPart = new IntEx(0);
thisPart.digits = new ArrayList<>();
for (int k = 0; k < i; k++)
thisPart.digits.add(0);
int Leftovers = 0;
for (int j = 0; j < target.digits.size(); j++)
{
int multiFragment = digits.get(i) * (int) target.digits.get(j) + Leftovers;
Leftovers = (int) (multiFragment / baseSize);
thisPart.digits.add((int)(multiFragment % baseSize));
}
while (Leftovers > 0)
{
thisPart.digits.add((int)(Leftovers % baseSize));
Leftovers = (int) (Leftovers / baseSize);
}
MultiParts.add(thisPart);
}
IntEx newNumber = new IntEx(0);
for (int i = 0; i < MultiParts.size(); i++)
{
newNumber.add(MultiParts.get(i));
}
digits = newNumber.digits;
}
public long longValue() throws Exception
{
int position = 0;
long multi = 1;
long retValue = 0;
if (digits.isEmpty()) return 0;
if (digits.size() > 16) throw new Exception("The number within IntEx class is too big to fit into a long");
do
{
retValue += digits.get(position) * multi;
multi *= baseSize;
position++;
} while (position < digits.size());
return retValue;
}
public static long BaseConvert(String number, String base)
{
boolean negative = number.startsWith("-");
number = number.replace("-", "");
ArrayList<Character> localDigits = new ArrayList<>();
for(int i = number.toCharArray().length - 1; i >=0; i--) {
localDigits.add(number.charAt(i));
}
// List<>().reverse is missing in this damn java. -_-
long retValue = 0;
long Multi = 1;
char[] CharsBase = base.toCharArray();
for (int i = 0; i < number.length(); i++)
{
int t = base.indexOf(localDigits.get(i));
retValue += base.indexOf(localDigits.get(i)) * Multi;
Multi *= base.length();
}
if (negative)
retValue = -retValue;
return retValue;
}
public static String BaseMult(String a, String b, String Base)
{
ArrayList<String> MultiParts = new ArrayList<>();
// this huge block is a tribute to java not having "Reverse()" method.
char[] x = new char[a.length()];
char[] y = new char[b.length()];
for(int i = 0; i < a.length(); i++) {
x[i] = a.charAt(a.length()-i);
}
for(int i = 0; i < b.length(); i++) {
y[i] = a.charAt(a.length()-i);
}
a = new String(x);
b = new String(y);
// ---------------------------------------------------------------------
for (int i = 0; i < a.length(); i++)
{
ArrayList<Character> thisPart = new ArrayList<>();
for (int k = 0; k < i; k++)
thisPart.add(Base.charAt(0));
int leftOvers = 0;
for (int j = 0; j < b.length(); j++)
{
// Need I say repeated characters in base may cause mayhem?
int MultiFragment = Base.indexOf(a.charAt(i)) * Base.indexOf(b.charAt(j)) + leftOvers;
leftOvers = MultiFragment / Base.length();
thisPart.add(Base.charAt(MultiFragment % Base.length()));
}
while (leftOvers > 0)
{
thisPart.add(Base.charAt(leftOvers % Base.length()));
leftOvers = leftOvers / Base.length();
}
char[] thisPartReverse = new char[thisPart.size()];
for(int z = 0; z < thisPart.size();z++)
thisPartReverse[z] = thisPart.get(thisPart.size()-z);
MultiParts.add(new String(thisPartReverse));
}
String retValue = ""+Base.charAt(0);
for (int i = 0; i < MultiParts.size(); i++)
{
retValue = BaseSum(retValue, MultiParts.get(i), Base);
}
return retValue;
}
public static String BaseSum(String a, String b, String Base)
{
// this huge block is a tribute to java not having "Reverse()" method.
char[] x = new char[a.length()];
char[] y = new char[b.length()];
for(int i = 0; i < a.length(); i++) {
x[i] = a.charAt(a.length()-i);
}
for(int i = 0; i < b.length(); i++) {
y[i] = a.charAt(a.length()-i);
}
a = new String(x);
b = new String(y);
// ---------------------------------------------------------------------
String greater = a.length() > b.length() ? a : b;
String lesser = a.length() < b.length() ? a : b;
int leftOvers = 0;
ArrayList<Character> result = new ArrayList();
for (int i = 0; i < greater.length() || leftOvers > 0; i++)
{
int sum;
if (i >= greater.length())
sum = leftOvers;
else if (i >= lesser.length())
sum = leftOvers + Base.indexOf(greater.charAt(i));
else
sum = Base.indexOf(a.charAt(i)) + Base.indexOf(b.charAt(i)) + leftOvers;
leftOvers = 0;
if (sum > Base.length()-1)
{
while (sum > Base.length()-1)
{
sum -= Base.length();
leftOvers += 1;
}
result.add(Base.charAt(sum));
}
else
{
result.add(Base.charAt(sum));
leftOvers = 0;
}
}
char[] reverseResult = new char[result.size()];
for(int i = 0; i < result.size(); i++)
reverseResult[i] = result.get(result.size() -i);
return new String(reverseResult);
}
public static String BaseConvertItoA(long number, String base)
{
ArrayList<Character> retValue = new ArrayList<>();
boolean negative = false;
long backup = number;
if (negative = (backup < 0))
backup = -backup;
do
{
int index = (int)(backup % base.length());
retValue.add(base.charAt(index));
backup = backup / base.length();
} while ((backup) > 0);
if (negative)
retValue.add('-');
char[] reverseRetVal = new char[retValue.size()];
for(int i = 0; i < retValue.size(); i++)
reverseRetVal[i] = retValue.get(retValue.size()-i);
return new String(reverseRetVal);
}
public String ToString(String base)
{
if(base == null || base.length() < 2)
base = "0123456789";
ArrayList<Character> retVal = new ArrayList<>();
char[] CharsBase = base.toCharArray();
int TamanhoBase = base.length();
String result = ""+base.charAt(0);
String multi = ""+base.charAt(1);
String lbase = IntEx.BaseConvertItoA(baseSize, base);
for (int i = 0; i < digits.size(); i++)
{
String ThisByte = IntEx.BaseConvertItoA(digits.get(i), base);
String Next = IntEx.BaseMult(ThisByte, multi, base);
result = IntEx.BaseSum(result, Next, base);
multi = IntEx.BaseMult(multi, lbase, base);
}
return result;
}
public static void main(String... args) {
int ref = 0;
IntEx result = new IntEx(0);
while(++ref <= 1000)
{
IntEx mul = new IntEx(1000);
for (int i = 0; i < 1000; ++i) {
mul.multiply(new IntEx(i));
}
result.add(mul);
}
System.out.println(result.toString());
}
}
Disclaimer: This is a rough translation/localization from a C# study, there are lots of code omitted. This is "almost" the same logics behind java.math.BigInteger (you can open BigInteger code on your favorite designer and check for yourself. If may I be forgetting a overloaded operator behind not translated to java, have a bit of patience and forgiveness, this example is just for a "maybe" clarification of the theory.
Also, just a sidenote, I know it is "Trying to reinvent the wheel", but considering this question has academic purpose I think its fairly rasonable to share.
One can see the result of this study on gitHub (not localized though), I'm not expanding that C# code here for its very extensive and not the language of this question.
This gives the correct answer without excess calculations. A Long is sufficient.
public String lastTen() {
long answer = 0;
String txtAnswer = "";
int length = 0;
int i = 1;
for(i = 1; i <= 1000; i++) {
answer += Math.pow(i, i);
txtAnswer = Long.toString(answer);
length = txtAnswer.length();
if(length > 9) break;
}
return txtAnswer.substring(length-10);
}
Related
I encountered a problem that I need to find the mirror of the prime numbers within the range of 1 to N. A mirror is like 13 and 31, 17 and 71, etc. I write the solution provided below,
/*
* find prime numbers within 1 to N that is a mirror to each other
*/
public static List<Integer> solution(int N) {
List<Integer> primes = findPrimes(N);
Set<Integer> set = new LinkedHashSet<>();
for (int i = 0; i < primes.size(); i++) {
int prime = primes.get(i);
int mirror = hasMirror(prime, primes);
if (mirror == 0) {
continue;
}
set.add(prime);
set.add(mirror);
}
return new ArrayList<>(set);
}
/*
* find the mirror of a number
* */
private static int findMirror(int P) {
int R = 0;
while (P != 0) {
int D = P % 10;
R = R * 10 + D;
P /= 10;
}
return R;
}
private static int hasMirror(int P, List<Integer> B) {
Integer[] A = B.toArray(new Integer[0]);
int N = A.length;
int R = findMirror(P);
for (int i = N - 1; i >= 0; i--) {
if (A[i] == R) {
return R;
}
}
return 0;
}
public static List<Integer> findPrimes(int N) {
int[] F = new int[N + 1];
List<Integer> result = new ArrayList<>();
for (int i = 2; i <= N; i++) {
if (F[i] == 0) {
// the prime value need to be 2 digit for the mirror image
if (i < 10 || i == findMirror(i)) {
continue;
}
result.add(i);
for (int k = i * i; k <= N; k += i) {
if (F[k] == 0) {
F[k] = 1;
}
}
}
}
return result;
}
}
The solution works, but, is there an option to improve the performance?
One thing you can do to improve performance is, not invoking the hasMirror() for already identified mirrors.
For example, let's say you checked 17 and identified that it has a mirror 71. Then when you reach 71 later on your loop, you can skip checking its mirrors as you have already identified it.
List<Integer> primes = findPrimes(N);
Set<Integer> set = new LinkedHashSet<>();
for (int i = 0; i < primes.size(); i++) {
int prime = primes.get(i);
if (!set.contains(prime)) {
int mirror = hasMirror(prime, primes);
if (mirror == 0) {
continue;
}
set.add(prime);
set.add(mirror);
}
}
The program I have currently takes N numbers and then a goal target. It inserts either "+" or "*" in between the numbers to try reach the goal. If it can reach the goal it will print out the correct operations.
However the way it finds the answer is by brute force, which is inadequate for a large set of N numbers. My current code is below:
public class Arithmetic4{
private static ArrayList<String> input = new ArrayList<String>();
private static ArrayList<String> second_line = new ArrayList<String>();
private static ArrayList<Integer> numbers = new ArrayList<Integer>();
private static ArrayList<String> operations = new ArrayList<String>();
private static ArrayList<Integer> temp_array = new ArrayList<Integer>();
public static void main(String [] args){
Scanner sc = new Scanner(System.in);
while(sc.hasNextLine()){
readInput(sc);
}
}
public static void readInput(Scanner sc){
String line = sc.nextLine();
input.add(line);
line = sc.nextLine();
second_line.add(line);
dealInput();
}
public static void dealInput(){
String numberS = input.get(0);
String[] stringNumbers = numberS.split("\\s+");
for(int i = 0; i < stringNumbers.length; i++){
String numberAsString = stringNumbers[i];
numbers.add(Integer.parseInt(numberAsString));
}
String orderString = second_line.get(0);
String[] stringWhatWay = orderString.split("\\s+");
int target = Integer.parseInt(stringWhatWay[0]);
char whatway = stringWhatWay[1].charAt(0);
long startTime = System.currentTimeMillis();
whatEquation(numbers, target, whatway);
long elapsedTime = System.currentTimeMillis() - startTime;
long elapsedMSeconds = elapsedTime / 1;
System.out.println(elapsedMSeconds);
numbers.clear();
input.clear();
second_line.clear();
}
public static void whatEquation(ArrayList<Integer> numbers, int target, char whatway){
if(whatway != 'L' && whatway != 'N'){
System.out.println("Not an option");
}
if(whatway == 'N'){
ArrayList<Integer> tempo_array = new ArrayList<Integer>(numbers);
int count = 0;
for (int y: numbers) {
count++;
}
count--;
int q = count;
calculateN(numbers, target, tempo_array, q);
}
if (whatway == 'L'){
if(numbers.size() == 1){
System.out.println("L " + numbers.get(0));
}
ArrayList<Integer> temp_array = new ArrayList<Integer>(numbers);
calculateL(numbers, target, temp_array);
}
}
public static void calculateN(ArrayList<Integer> numbers, int target, ArrayList<Integer> tempo_numbers, int q){
int sum = 0;
int value_inc = 0;
int value_add;
boolean firstRun = true;
ArrayList<Character> ops = new ArrayList<Character>();
ops.add('+');
ops.add('*');
for(int i = 0; i < Math.pow(2, q); i++){
String bin = Integer.toBinaryString(i);
while(bin.length() < q)
bin = "0" + bin;
char[] chars = bin.toCharArray();
List<Character> oList = new ArrayList<Character> ();
for(char c: chars){
oList.add(c);
}
ArrayList<Character> op_array = new ArrayList<Character>();
ArrayList<Character> temp_op_array = new ArrayList<Character>();
for (int j = 0; j < oList.size(); j++) {
if (oList.get(j) == '0') {
op_array.add(j, ops.get(0));
temp_op_array.add(j, ops.get(0));
} else if (oList.get(j) == '1') {
op_array.add(j, ops.get(1));
temp_op_array.add(j, ops.get(1));
}
}
sum = 0;
for(int p = 0; p < op_array.size(); p++){
if(op_array.get(p) == '*'){
int multiSum = numbers.get(p) * numbers.get(p+1);
numbers.remove(p);
numbers.remove(p);
numbers.add(p, multiSum);
op_array.remove(p);
p -= 1;
}
}
for(Integer n: numbers){
sum += n;
}
if(sum != target){
numbers.clear();
for (int t = 0; t < tempo_numbers.size(); t++) {
numbers.add(t, tempo_numbers.get(t));
}
}
if (sum == target){
int count_print_symbol = 0;
System.out.print("N ");
for(int g = 0; g < tempo_numbers.size(); g++){
System.out.print(tempo_numbers.get(g) + " ");
if(count_print_symbol == q){
break;
}
System.out.print(temp_op_array.get(count_print_symbol) + " ");
count_print_symbol++;
}
System.out.print("\n");
return;
}
}
System.out.println("N is Impossible");
}
public static void calculateL(ArrayList<Integer> numbers, int target, ArrayList<Integer> temp_array){
int op_count = 0;
int sum = 0;
int n = (numbers.size() -1);
boolean firstRun = true;
for (int i = 0; i < Math.pow(2, n); i++) {
String bin = Integer.toBinaryString(i);
while (bin.length() < n)
bin = "0" + bin;
char[] chars = bin.toCharArray();
char[] charArray = new char[n];
for (int j = 0; j < chars.length; j++) {
charArray[j] = chars[j] == '0' ? '+' : '*';
}
//System.out.println(charArray);
for(char c : charArray){
op_count++;
if(firstRun == true){
sum = numbers.get(0);
numbers.remove(0);
// System.out.println(sum);
}
if (!numbers.isEmpty()){
if (c == '+') {
sum += numbers.get(0);
} else if (c == '*') {
sum *= numbers.get(0);
}
numbers.remove(0);
}
firstRun = false;
//System.out.println(sum);
if(sum == target && op_count == n){
int count_print_op = 0;
System.out.print("L ");
for(int r = 0; r < temp_array.size(); r++){
System.out.print(temp_array.get(r) + " ");
if(count_print_op == n){
break;
}
System.out.print(charArray[count_print_op] + " ");
count_print_op++;
}
System.out.print("\n");
return;
}
if(op_count == n && sum != target){
firstRun = true;
sum = 0;
op_count = 0;
for(int e = 0; e < temp_array.size(); e++){
numbers.add(e, temp_array.get(e));
}
}
}
}
System.out.println("L is impossible");
}
}
Is there a faster to way to reach a similar conclusion?
This problem can be solved in O(NKĀ²) using the Dynamic Programming paradigm, where K is the maximum possible value for the goal target. This is not that good and maybe there is a faster algorithm, but it's still a lot better than the O(2^N) brute force solution.
First let's define a recurrence to solve the problem: let G be the goal value and f(i,j,k) be a function that returns:
1 if we can reach the value G-j-k using only elements from index i and onwards
0 otherwise
We are going to use j as an accumulator that holds the current total sum and k as an accumulator that holds the total product of the current chain of multiplications, you will understand it soon.
The base cases for the recurrence are:
f(N,x,y) = 1 if x+y = G (we have used every element and reached our goal)
f(N,x,y) = 0 otherwise
f(i,x,y) = 0 i != N and x+y >= G (we have exceeded the goal before using every element)
For other i values we can define the recurrence as:
f(i,j,k) = max( f(i+1,j+k,v[i]) , f(i+1,j,k*v[i]) )
The first function call inside max() means that we will put a "+" sign before the current index, so our current multiplication chain is broken and we have to add its total product to the current sum, so the second parameter is j+k, and since we are starting a new multiplication chain right now, it's total product is exactly v[i].
The second function call inside max() means that we will put a "*" sign before the current index, so our current multiplication chain is still going on, so the second parameter remains j, and the third parameter will become k * v[i].
What we want is the value of f(0,0,0) (we haven't used any elements, and our current accumulated sums are equal to 0). f(0,0,0) equals 1 if and only if there is a solution for the problem, so the problem is solved. Now let's go back to the recurrence and fix a detail: when we run f(0,0,0), the value of k*v[i] will be 0 no matter the value of v[i], so we have to add a special check when we are computing the answer for i = 0, and the final recurrence will look like this:
f(i,j,k) = max( f(i+1,j+k,v[i]) , f(i+1,j,(i==0?v[i]:k*v[i])) )
Finally, we apply the memoization/dynamic programming paradigm to optimize the calculation of the recurrence. During the execution of the algorithm, we will keep track of every calculated state so when this state is called again by another recursive call we just return the stored value instead of computing its whole recursion tree again. Don't forget to do this or your solution is going to be as slow as a brute force solution (or even worse) due to recalculation of subproblems. If you need some resources on DP, you can start here: https://en.wikipedia.org/wiki/Dynamic_programming
My program displays Pascal's triangle. For enlarging the portion of the triangle that may be calculated and displayed, I've rewritten the code using BigInteger instead of primitive types.
Here's the code:
import java.math.BigInteger;
public class ptrig {
public static void main(String args[]) {
BigInteger no = BigInteger.valueOf(5);
// Creating the array
String doubledim[][] = new String[no.intValue()][];
BigInteger k;
for (k = BigInteger.ZERO; k.compareTo(no) < 0; k.add(BigInteger.ONE)) {
doubledim[k.intValue()] = new String[k.intValue() + BigInteger.ONE.intValue()];
}
// Assigning values
BigInteger i, j, p, n;
BigInteger l = BigInteger.ONE;
for (i = BigInteger.ZERO; i.compareTo(no) < 0; i.add(BigInteger.ONE)) {
for (j = BigInteger.ZERO; j.compareTo(i.add(BigInteger.ONE)) < 0; j.add(BigInteger.ONE)) {
BigInteger m = i.subtract(j);
if (j.compareTo(m) > 0) {
for (p = BigInteger.ZERO; p.compareTo(m) < 0; p = p.add(BigInteger.ONE)) {
n = i.subtract(p);
l = l.multiply(n);
}
doubledim[i.intValue()][j.intValue()] = l.divide(factorial.factmet(m)).toString();
l = BigInteger.ONE;
}
if (m.compareTo(j) > 0) {
for (p = BigInteger.ZERO; p.compareTo(j) < 0; p = p.add(BigInteger.ONE)) {
n = i.add(p.add(BigInteger.ONE)).subtract(j);
l = l.multiply(n);
}
doubledim[i.intValue()][j.intValue()] = l.divide(factorial.factmet(j)).toString();
l = BigInteger.ONE;
}
if (m.compareTo(j) == 0) {
for (p = BigInteger.ZERO; p.compareTo(j) < 0; p = p.add(BigInteger.ONE)) {
n = i.subtract(p);
l = l.multiply(n);
}
doubledim[i.intValue()][j.intValue()] = l.divide(factorial.factmet(j)).toString();
l = BigInteger.ONE;
}
}
}
// Printing
for (i = BigInteger.ZERO; i.compareTo(no) < 0; i.add(BigInteger.ONE)) {
for (j = BigInteger.ZERO; j.compareTo(i.add(BigInteger.ONE)) < 0; j.add(BigInteger.ONE)) {
System.out.print(doubledim[i.intValue()][j.intValue()] + " ");
}
System.out.println();
}
}
}
The problem is it displays nothing. I've read on Stack Overflow I need to convert the array values into strings for that they're displayed, so I did. I've also checked the System.out.println statements - they seem to be fine. The error persisted.
The algorithm itself worked fine on a previous version with primitive types.
What's the error here? I did my best to find an answer on the web, I couldn't. Thanks.
Your for-loops aren't incrementing their indices, and will therefor loop forever.
i.add(BigInteger.ONE) doesn't mutate i, it creates a new BigInteger and returns it. If you want to increment the value of i, you need to write i = i.add(BigInteger.ONE)
This means that when you try to initialize your array, you're entering an infinite loop, where you re-initialize doubledim[0] forever.
e.g.
for (k = BigInteger.ZERO; k.compareTo(no) < 0; k.add(BigInteger.ONE)) {
doubledim[k.intValue()] = new String[k.intValue() + BigInteger.ONE.intValue()];
}
should be
for (k = BigInteger.ZERO; k.compareTo(no) < 0; k = k.add(BigInteger.ONE)) {
doubledim[k.intValue()] = new String[k.intValue() + BigInteger.ONE.intValue()];
}
and you'll need to likewise fix the loops that control the population of data in your arrays, and printing of their data later in your program.
I'm a total beginner of java.
I have a homework to write a complete program that calculates the factorial of 50 using array.
I can't use any method like biginteger.
I can only use array because my professor wants us to understand the logic behind, I guess...
However, he didn't really teach us the detail of array, so I'm really confused here.
Basically, I'm trying to divide the big number and put it into array slot. So if the first array gets 235, I can divide it and extract the number and put it into one array slot. Then, put the remain next array slot. And repeat the process until I get the result (which is factorial of 50, and it's a huge number..)
I tried to understand what's the logic behind, but I really can't figure it out.. So far I have this on my mind.
import java.util.Scanner;
class Factorial
{
public static void main(String[] args)
{
int n;
Scanner kb = new Scanner(System.in);
System.out.println("Enter n");
n = kb.nextInt();
System.out.println(n +"! = " + fact(n));
}
public static int fact(int n)
{
int product = 1;
int[] a = new int[100];
a[0] = 1;
for (int j = 2; j < a.length; j++)
{
for(; n >= 1; n--)
{
product = product * n;
a[j-1] = n;
a[j] = a[j]/10;
a[j+1] = a[j]%10;
}
}
return product;
}
}
But it doesn't show me the factorial of 50.
it shows me 0 as the result, so apparently, it's not working.
I'm trying to use one method (fact()), but I'm not sure that's the right way to do.
My professor mentioned about using operator / and % to assign the number to the next slot of array repeatedly.
So I'm trying to use that for this homework.
Does anyone have an idea for this homework?
Please help me!
And sorry for the confusing instruction... I'm confused also, so please forgive me.
FYI: factorial of 50 is 30414093201713378043612608166064768844377641568960512000000000000
Try this.
static int[] fact(int n) {
int[] r = new int[100];
r[0] = 1;
for (int i = 1; i <= n; ++i) {
int carry = 0;
for (int j = 0; j < r.length; ++j) {
int x = r[j] * i + carry;
r[j] = x % 10;
carry = x / 10;
}
}
return r;
}
and
int[] result = fact(50);
int i = result.length - 1;
while (i > 0 && result[i] == 0)
--i;
while (i >= 0)
System.out.print(result[i--]);
System.out.println();
// -> 30414093201713378043612608166064768844377641568960512000000000000
Her's my result:
50 factorial - 30414093201713378043612608166064768844377641568960512000000000000
And here's the code. I hard coded an array of 100 digits. When printing, I skip the leading zeroes.
public class FactorialArray {
public static void main(String[] args) {
int n = 50;
System.out.print(n + " factorial - ");
int[] result = factorial(n);
boolean firstDigit = false;
for (int digit : result) {
if (digit > 0) {
firstDigit = true;
}
if (firstDigit) {
System.out.print(digit);
}
}
System.out.println();
}
private static int[] factorial(int n) {
int[] r = new int[100];
r[r.length - 1] = 1;
for (int i = 1; i <= n; i++) {
int carry = 0;
for (int j = r.length - 1; j >= 0; j--) {
int x = r[j] * i + carry;
r[j] = x % 10;
carry = x / 10;
}
}
return r;
}
}
How about:
public static BigInteger p(int numOfAllPerson) {
if (numOfAllPerson < 0) {
throw new IllegalArgumentException();
}
if (numOfAllPerson == 0) {
return BigInteger.ONE;
}
BigInteger retBigInt = BigInteger.ONE;
for (; numOfAllPerson > 0; numOfAllPerson--) {
retBigInt = retBigInt.multiply(BigInteger.valueOf(numOfAllPerson));
}
return retBigInt;
}
Please recall basic level of math how multiplication works?
2344
X 34
= (2344*4)*10^0 + (2344*3)*10^1 = ans
2344
X334
= (2344*4)*10^0 + (2344*3)*10^1 + (2344*3)*10^2= ans
So for m digits X n digits you need n list of string array.
Each time you multiply each digits with m. and store it.
After each step you will append 0,1,2,n-1 trailing zero(s) to that string.
Finally, sum all of n listed string. You know how to do that.
So up to this you know m*n
now it is very easy to compute 1*..........*49*50.
how about:
int[] arrayOfFifty = new int[50];
//populate the array with 1 to 50
for(int i = 1; i < 51; i++){
arrayOfFifty[i-1] = i;
}
//perform the factorial
long result = 1;
for(int i = 0; i < arrayOfFifty.length; i++){
result = arrayOfFifty[i] * result;
}
Did not test this. No idea how big the number is and if it would cause error due to the size of the number.
Updated. arrays use ".length" to measure the size.
I now updated result to long data type and it returns the following - which is obviously incorrect. This is a massive number and I'm not sure what your professor is trying to get at.
-3258495067890909184
I'm trying to generate ten large prime numbers. here is my code. I use small numbers to see if it's working.
public static void primeGenerator(){
BigInteger[] primeList = new BigInteger[10];
BigInteger startLine = new BigInteger("1");
int startPower = 1;
BigInteger endLine = new BigInteger("10");
int endPower = 2;
int j = 0;
for (BigInteger i = startLine.pow(startPower);
i.compareTo(endLine.pow(endPower)) <= 0;
i = i.add(BigInteger.ONE)) {
if(checkPrimeFermat(i) == true && j<10)
primeList[j] = i;
j++;
continue;
}
System.out.print(primeList[3]);
}
the outputs:
primeList[0] = null primeList[1] = 2 primeList[2] = 3 primeList[3] = null
outputs I want to generate:
primeList[0] = 2 primeList[1] = 3 primeList[2] = 5 primeList[3] = 7
when the j comes the 4 code didn't check 5 and stop in here. How can I solve this problem? I tested checkPrimeFermat with junit it's working by the way.
This'll work:
public static void primeGenerator() {
BigInteger[] primeList = new BigInteger[10];
BigInteger startLine = new BigInteger("1");
int startPower = 1;
BigInteger endLine = new BigInteger("10");
int endPower = 2;
int j = 0;
for (BigInteger i = startLine.pow(startPower); i.compareTo(endLine
.pow(endPower)) <= 0; i = i.add(BigInteger.ONE)) {
if (checkPrimeFermat(i) == true && j < 10) {
primeList[j] = i;
j++;
}
}
System.out.print(Arrays.toString(primeList));
}