user19435242
user19435242

Reputation:

How to prevent a recursive method from changing a value of a variable?

I'm learning Java, and I'm stuck on a recursion problem.

I need to use a recursive method to check if a number is an Armstrong number or not.

My code:

public class ArmstrongChecker {

    public boolean isArmstrong(int number) {
        // check if the number is a negative number
        if (number < 0) {
            return false;
        }
        ArmstrongChecker armstrongChecker = new ArmstrongChecker();
        // find the length of the number
        int length = armstrongChecker.lengthChecker(number);
        // create a variable to store the sum of the digits of the number
        int sum = 0;
        // find the individual digits and raise to the power of the numbers of digits
        if (number != 0) {
            int digit = Math.floorMod(number, 10);
            int powerRaised = (int) Math.pow(digit, length);
            sum = sum + powerRaised;
            isArmstrong(number / 10);
        }
        return sum == number;
    }

    // method to check the length of the number
    public int lengthChecker(int number) {
        int length = String.valueOf(number).length();
        return length;
    }
}

How do I prevent int length in isArmstrong() method from changing its value.

Upvotes: 3

Views: 785

Answers (3)

David Conrad
David Conrad

Reputation: 16359

You need to get the length once for whole recursion, so the cleanest approach would be to pass down both the number and the length into the recursion. An easy way to do this is to have one method that is the public face of the API, and another that does the recursion.

public class ArmstrongChecker {
    public boolean isArmstrong(int number) {
        if (number < 0) {
            return false;
        }
        int length = lengthChecker(number);
        int sum = armstrongSum(number, length);
        return sum == number;
    }

    private int armstrongSum(int number, int length) {
        int sum = 0;
        if (number != 0) {
            int digit = Math.floorMod(number, 10);
            int powerRaised = (int) Math.pow(digit, length);
            sum += powerRaised;
            sum += armstrongSum(number / 10, length);
        }
        return sum;
    }

    public int lengthChecker(int number) {
        int length = String.valueOf(number).length();
        return length;
    }
}

This is pretty common in recursion, where the parameters to the recursive part of the algorithm are a little different (usually there are more of them) than what you want a client of the API to have to pass in. The number changes in each recursive call, where number / 10 is passed down, but the same length is passed all the way through.

Notice that the recursive armstrongSum uses the return value from the recursive call, and that there is no need to create another instance of ArmstrongChecker when you are already in an instance method of the class.

Upvotes: 0

Alexander Ivanchenko
Alexander Ivanchenko

Reputation: 28988

As I've already said in the comments, your solution has the following issues:

  • The result of the recursive call isArmstrong() is being ignored;
  • There's no need for spawning new instances of ArmstrongChecker. And this method doesn't require object creation at all, it can be implemented as static.
  • Checking if the number is an Armstrong number boils down to calculating its Armstrong sum, the solution will be cleaner if you implement only this part using recursion.

It might look like this:

public static boolean isArmstrong(int number) {
    if (number < 0) return false;
    if (number < 10) return true;
    
    return number == getArmstrongSum(number, String.valueOf(number).length());
}

public static int getArmstrongSum(int number, int power) {
    if (number == 0) {
        return 0;
    }
    return (int) Math.pow(number % 10, power) + getArmstrongSum(number / 10, power);
}

main()

public static void main(String[] args) {
    System.out.println(isArmstrong(370)); // true
    System.out.println(isArmstrong(12));  // false
    System.out.println(isArmstrong(54));  // false
    System.out.println(isArmstrong(153)); // true
}

Output:

true
false
false
true

Upvotes: 1

queeg
queeg

Reputation: 9384

While you are not changing it's value in the posted code, you could mark that variable to be a constant. This way the compiler can error out if you tried to assign a new value.

final int length = armstrongChecker.lengthChecker(number);

Upvotes: 1

Related Questions