Java program for factorial incorrect output - java

I am executing the below piece of Java code in Eclipse IDE.
public class Programs {
public static void main(String[] args) {
// TODO Auto-generated method stub
int i, num, n;
n = 6;
// num=n-1;
for (i = 1; i <= n - 1; i++) {
n = n * i;
}
System.out.println("Factorial of the declared number is" + " " + n);
}
}
It shows the output as -1420957696. The code works fine if I uncomment and use the "num" variable in the for loop. I think for every iteration the value of n changes gradually incredibly as compared to value of i. The same code works fine in VBScript (see below). Can anyone explain the difference?
Option Explicit
Dim i, num
num = InputBox("enter a number")
For i=1 To num-1
num = num * i
Next
MsgBox "The factorial of entered number is: " & num, 3, "Program for factorial"

Java:
n is going to get rather big cf. i.
Therefore i <= n - 1 will always be true, until your n overflows and wraps around to a negative.
One fix would be to use num to hold the original value of n, and use i <= num - 1 as the stopping condition.
VBScript:
In the various basics (E.g. VBScript, VBA), num-1 is effectively computed at the start of the loop, and further adjustment to num have no effect on the stopping condition. You can see this explicitly by running
Dim j
Dim i
j = 10
For i = 1 To j
WScript.Echo i
j = 1 'has no effect on the stopping condition.
Next

every iteration in the forloop i<=n-1 is checked. Because n is increased all the time, the for loop will run until n reaches the highest possible number of INTEGER and becomes negative.

you are not storing previous multiplication in another variable and your n is always increasing so the condition in for for i changes every iteration.

As mentioned in the above answers evaluation of the condition causes the exception. What you can do is keep a separate variable to check the condition in the loop like this.
int i,fact=1;
int number=5;//Number to calculate factorial
for(i=1;i<=number;i++){
fact=fact*i;
}

it comes down to when numbers are read compared to when they are set:
n = 6;
for (i = 1; i <= n - 1; i++) {
n = n * i;
}
What java will do is:
Set i = 1, do the check i <= n-1 (1 <= 5) then execute the code in the braces, then increment i (i++).
Then this is repeated:
i is now equal to 2, do the check i <= n-1 (2 <= 4) n has changed in the last iteration so the check will use the new value. so on the next iteration n = 12.
This causes n to grow faster than i so when the capacity of an integer is exceeded causing n to go negative the loop condition resolves to false.
The answer is to not modify the value in your loop condition inside the loop.
n = 6;
num = n - 1;
for (i = 1; i <= num; i++) {
n = n * i;
}
The way the loop is working for VB is by calculating the numbers for the beginning and end of the loop when it is started, meaning that num was only read once.

You are not storing previous multiplication in another variable and your n is always increasing so the condition in for i changes every iteration.
Instead you can have separate variable to hold your factorial.
class FactorialExample{
public static void main(String args[]){
int i,fact=1;
int number=5;//It is the number to calculate factorial
for(i=1;i<=number;i++){
fact=fact*i;
}
System.out.println("Factorial of "+number+" is: "+fact);
}
}
Hope that Helps.

Related

I don't understand the why is sum = 0?

I'm studying a Java course in Udemy. We have a challenge question, i understand most of the code but not this: sum= 0;
I've asked the teacher on Udemy but no answer.
So here's the challenge:
Write a method called isOdd with an int parameter and call it number. The method needs to return a boolean. Check that number is > 0, if it is not return false.
Write a second method called sumOdd that has 2 int parameters: start and end, whoch reperesent a range of numbers.
The method should use a for loop to sum all odd numbers in that range including the "end" and return the sum.
The method is called isOdd to check if each number is odd.
The parameter end needs to be greater than or equal to start and both start and end parameters have to be greater than 0.
If those methods are not satisfied, return -1.
In the challenge on udemy if i don't type sum = 0 i.e: sum = 10 it gives an error. I don't get why sum = 0?
class SumOddRange {
public static void main(String[] args) {
sumOdd(15, 13);
isOdd(10);
}
public static boolean isOdd(int number) {
if (number < 0) {
return false;
} else if (number % 2 != 0) {
return true;
} else {
return false;
}
}
public static int sumOdd(int start, int end) {
if((end < start) || (start <= 0)) {
return -1;}
int sum = 0;
for (int i = start; i <= end; i++) {
if (isOdd(i)) {
sum += i;
}
}
return sum;
}
}
In
int sum = 0;
the = 0 part is an initialization of variable sum. That is, it specifies that variable's initial value, almost exactly as if you instead wrote
int sum;
sum = 0;
Local variables have no defined value (and you may not use their values) until a value is first assigned, so it is necessary to provide an initial value via one of those two forms.
As for why you must specifically initialize that variable to 0, that's because it's the correct value to make the rest of your method implementation work as required. If you initialize it differently then the method will return a different value for the same arguments.
Semantically speaking, sum records a running sum of the odd numbers processed so far, and before you've processed any, the sum of those processed so far should indeed be zero. That may even be your method's final return value, such as when you invoke SumOddRange.sumOdd(2,2).
Note: do not confuse the assignment operator, =, with the equality-test operator, ==.
When you sum up a series of numbers, you must first initialize the sum with the identity value of 0.
So
int sum = 0;
sum = sum + 10; // now sum is 10
sum = sum + 20; // now sum is 30
If you had been taking the product of a series of numbers would have initialized prod to 1.
int prod = 1;
prod = prod * 5; // now prod is 5
prod = prod * 7; // now prod is 35
Note that you need to assign a value to accept the sum. So
int sum = sumOdd(15,13);
should return -1 since 13 < 15 which is an error in your method.
You have to create the variable sum to start at 0. It's like if you were counting marbles or something. No one ever says 0 at the start of their counting, because it's obvious that you would start at 0. Yet, a computer doesn't know that, so you have to tell it at the beginning of the loop that the current sum is 0. Then you can use the loop and add to your sum as you count.
If you don't say sum is 0, then when you say "sum += i" in the loop, you will get an error, because the computer doesn't know what sum started out as.

Simple program using loops (Beginning Java)

I have to write a program using loops that calculates the sum of all odd numbers between a and b (inclusive), where a and b are inputs.
I made this (below) and it works fine, but I noticed one problem with it: when i enter a larger number followed by a smaller number for the inputs, it returns 0, but when i enter the smaller number first it works perfectly. Any quick fixes for this? :)
import java.util.Scanner;
public class ComputeSumAAndB
{
public static void main (String[] args)
{
Scanner in = new Scanner(System.in);
System.out.print("Please enter 2 integers: "); //prompts user for ints
int a = in.nextInt();
int b = in.nextInt();
int sum = 0;
for (int j = a; j <= b; j++)
{
if (j % 2 == 1)
sum += j;
}
System.out.println("The sum of all odd numbers (inclusive) between " + a + " and "+ b + " is " + sum);
}
}
int temp;
if(a > b) {
temp = a;
a = b;
b = temp;
}
Put this right before your for loop starts.
The if checks whether a (the first number entered) is larger than b. If it is, it swaps a and b. Now your for loop will always start with the smallest number and iterate up to the larger number (because after this if, a will always be the smaller number).
Using this method has the added side effect of making your output make sense. Your output will now always say: "between [smaller number] and [larger number]".
rolfl's answer is more elegant and works perfectly fine, but when the user enters the larger number first, your output may look kind of weird: "between [larger number] and [smaller number]", etc.
You can get the smaller and larger inputs by using the Math.min() and Math.max functions....
for (int j = Math.min(a,b); j <= Math.max(a,b); j++) {
if (j % 2 == 1) {
sum += j;
}
}
It's not working because A is larger than B in the for loop, you have it iterate while A is less than or equal to B.
You could do what nhgrif says but it's changing your data.. But he is correct.
That's because you are first expecting for the a input (inferior limit) and then the b (superior). When your program reaches the for, j = a so the condition a <= b is False, if the first input is larger. In other words it never enters the for loop.
Actually you should do the following 2 things:
1 It is just just like rolfl mentioned above. You need to put the min and max in the right place in loop.
for (int j = Math.min(a,b); j <= Math.max(a,b); j++)
{
if (j % 2 == 1) {
sum += j;
}
}
2 Use if (j % 2 == 1) it is not enough to check whether the num is odd.
e.g.
a = -5, b =0;
What will be the result?
int sum = 0;
for(int j=-5;j<0;j++)
{
if(j%2 == 1)
{
sum+=j;
}
}
The value for sum will be 0.
We need to change the condition to if(!(j%2 == 0)) Then you will get the expected result.
That's because you are first expecting for the a input (inferior limit) and then the b (superior). When your program reaches the for, j = a so the condition a <= b is False, if the first input is larger. In other words it never enters the for loop.

How to determine how often a statement in a nested loop is executed?

I am working through a section of a text on determining complexity of nested loops using recurrence relations. In this particular example I am trying to determine how many times the count variable will be incremented as a function of n.
This is the loop I am analyzing:
for (int i = 1; i <= n; i++) {
int j = n;
while (j > 0) {
count++;
j = j / 2;
}
}
I think I understand that the first line would equate simply to n since it only executes for each value of n but it's the rest of it that I'm having trouble with. I think the answer would be something like n(n/2) except that this example is using integer division so I'm not sure how to represent that mathematically.
I've run through the loop by hand a few times on paper so I know that the count variable should equal 1, 4, 6, 12, 15, and 18 for n values of 1-6. I just can't seem to come up with the formula... Any help would be greatly appreciated!
The loop executes for n in the range [1, n]. It divides by 2 each time for the j variable, which is set to n, so the number of time the inner loop executes is floor(l2(n)) + 1, where l2 is the binary log function. Add up all such values from 1 to n (multiply by n).
The inner j loop adds the location of the first set bit to count.
Each divide by 2 is the same as a right shift until all the bits are zero.
So, 2 would be 10 in binary, and have a value of 2 for the inner loop.
4 would be 100 in binary, and have a value of 3 for the inner loop.
The outer loop seems to just multiply the location of the first set bit by the number itself.
Here is an example with n = 13.
13 in binary is 1101, so the first set bit is at location 4.
4 * 13 = 52. 52 is the final answer.
for (int i = 1; i <= n; i++) {
This loop at the top goes through the loop n times.
int j = n;
while (j > 0) {
count++;
j = j / 2;
}
This loop here goes through the loop log(n) times, noting that it is a base 2 log since you are dividing by 2 each time.
Hence, the total number of counts is n * ceiling(log(n))

I need to make two to the input value inclusive

/*
* Application the reads an integer and prints sum of all even integers between two and input value
*/
import java.util.Scanner;
public class evenNumbers{
public static void main(String [] args){
int number;
Scanner scan = new Scanner(System.in);
System.out.println("Enter an Integer greater than 1:");
number = scan.nextInt();
printNumber(number);
}// end main
/*declares an int variable called number and displays it on the screen*/
public static void printNumber(int number){
if (number < 2){
System.out.println("Input value must not be less than 2");
}
int sum = 2;
if(number % 2==0){
sum+= number;
}
System.out.println("Sum of even numbers between 2 and " + number + " inclusive is: " + sum);
}//end printnumber
}
I need to calculate the sum of 2 to the input number inclusive however, it only takes the last number and add two to it. COuld someone help me fix this.
You need a loop. Your comment hints at the right direction, but you should look at the Java tutorials to see how to correctly write a 'for' loop. There are three parts: the initial declaration, the terminating condition and the loop step. Remember that the ++ operator only adds one to the variable. You can add other values using +=. If you use += to add a different value (like 2) to the loop variable, you can skip the 'if' test for even numbers. You can test for boundaries inclusively using the <= and >= comparison operators (for primitives). So you want something like this (in pseudocode, not Java):
input the test value
Optional: reject invalid test value and **exit with message if it is not valid!**
initialize the sum variable to zero
for ( intialize loop variable to 2; test that loop var <= test value; add 2 to loop var )
{
add 'number' to the sum variable
}
display the sum
int sum = 0;
for (int current = 2; current <= number; current += 2)
sum += current;

Prime factorization algorithm fails for big numbers

I have run into a weird issue for problem 3 of Project Euler. The program works for other numbers that are small, like 13195, but it throws this error when I try to crunch a big number like 600851475143:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at euler3.Euler3.main(Euler3.java:16)
Here's my code:
//Number whose prime factors will be determined
long num = 600851475143L;
//Declaration of variables
ArrayList factorsList = new ArrayList();
ArrayList primeFactorsList = new ArrayList();
//Generates a list of factors
for (int i = 2; i < num; i++)
{
if (num % i == 0)
{
factorsList.add(i);
}
}
//If the integer(s) in the factorsList are divisable by any number between 1
//and the integer itself (non-inclusive), it gets replaced by a zero
for (int i = 0; i < factorsList.size(); i++)
{
for (int j = 2; j < (Integer) factorsList.get(i); j++)
{
if ((Integer) factorsList.get(i) % j == 0)
{
factorsList.set(i, 0);
}
}
}
//Transfers all non-zero numbers into a new list called primeFactorsList
for (int i = 0; i < factorsList.size(); i++)
{
if ((Integer) factorsList.get(i) != 0)
{
primeFactorsList.add(factorsList.get(i));
}
}
Why is it only big numbers that cause this error?
Your code is just using Integer, which is a 32-bit type with a maximum value of 2147483647. It's unsurprising that it's failing when used for numbers much bigger than that. Note that your initial loop uses int as the loop variable, so would actually loop forever if it didn't throw an exception. The value of i will go from the 2147483647 to -2147483648 and continue.
Use BigInteger to handle arbitrarily large values, or Long if you're happy with a limited range but a larger one. (The maximum value of long / Long is 9223372036854775807L.)
However, I doubt that this is really the approach that's expected... it's going to take a long time for big numbers like that.
Not sure if it's the case as I don't know which line is which - but I notice your first loop uses an int.
//Generates a list of factors
for (int i = 2; i < num; i++)
{
if (num % i == 0)
{
factorsList.add(i);
}
}
As num is a long, its possible that num > Integer.MAX_INT and your loop is wrapping around to negative at MAX_INT then looping until 0, giving you a num % 0 operation.
Why does your solution not work?
Well numbers are discrete in hardware. Discrete means thy have a min and max values. Java uses two's complement, to store negative values, so 2147483647+1 == -2147483648. This is because for type int, max value is 2147483647. And doing this is called overflow.
It seems as if you have an overflow bug. Iterable value i first becomes negative, and eventually 0, thus you get java.lang.ArithmeticException: / by zero. If your computer can loop 10 million statements a second, this would take 1h 10min to reproduce, so I leave it as assumption an not a proof.
This is also reason trivially simple statements like a+b can produce bugs.
How to fix it?
package margusmartseppcode.From_1_to_9;
public class Problem_3 {
static long lpf(long nr) {
long max = 0;
for (long i = 2; i <= nr / i; i++)
while (nr % i == 0) {
max = i;
nr = nr / i;
}
return nr > 1 ? nr : max;
}
public static void main(String[] args) {
System.out.println(lpf(600851475143L));
}
}
You might think: "So how does this work?"
Well my tough process went like:
(Dynamical programming approach) If i had list of primes x {2,3,5,7,11,13,17, ...} up to value xi > nr / 2, then finding largest prime factor is trivial:
I start from the largest prime, and start testing if devision reminder with my number is zero, if it is, then that is the answer.
If after looping all the elements, I did not find my answer, my number must be a prime itself.
(Brute force, with filters) I assumed, that
my numbers largest prime factor is small (under 10 million).
if my numbers is a multiple of some number, then I can reduce loop size by that multiple.
I used the second approach here.
Note however, that if my number would be just little off and one of {600851475013, 600851475053, 600851475067, 600851475149, 600851475151}, then my approach assumptions would fail and program would take ridiculously long time to run. If computer could execute 10m statements per second it would take 6.954 days, to find the right answer.
In your brute force approach, just generating a list of factors would take longer - assuming you do not run out of memory before.
Is there a better way?
Sure, in Mathematica you could write it as:
P3[x_] := FactorInteger[x][[-1, 1]]
P3[600851475143]
or just FactorInteger[600851475143], and lookup the largest value.
This works because in Mathematica you have arbitrary size integers. Java also has arbitrary size integer class called BigInteger.
Apart from the BigInteger problem mentioned by Jon Skeet, note the following:
you only need to test factors up to sqrt(num)
each time you find a factor, divide num by that factor, and then test that factor again
there's really no need to use a collection to store the primes in advance
My solution (which was originally written in Perl) would look something like this in Java:
long n = 600851475143L; // the original input
long s = (long)Math.sqrt(n); // no need to test numbers larger than this
long f = 2; // the smallest factor to test
do {
if (n % f == 0) { // check we have a factor
n /= f; // this is our new number to test
s = (long)Math.sqrt(n); // and our range is smaller again
} else { // find next possible divisor
f = (f == 2) ? 3 : f + 2;
}
} while (f < s); // required result is in "n"

Categories