Why does my fast exponentiation algorithm give me a 'cannot find symbol' error in the parameter of a lambda?

Jodast :

Background/Goal I am trying to accomplish:

I am attempting to implement the fast exponentiation algorithm in Java from scratch (as practice). The algorithm is as follows (explanation taken from johndcook.com):

Input: base b, exponent n.

Write the exponent n in binary. Read the binary representation from left to right, starting with the second bit from the left. Start with the number a, and every time you read a 0 bit, square what you’ve got. Every time you read a 1 bit, square what you’ve got and multiply by a. It follows that an can be computed using no more than 2 log2(n) multiplications.

I am not looking for a better way to implement this algorithm, but rather why I am getting this particular error.

What the problem is

I tried to implement this algorithm using a recursive lambda in Java, and when I went to run the program, I got the following errors:

Main.java:11: error: cannot find symbol

exponentiator = (int runningResult, int binLength, int binInt, int expBase) -> {
                                                               ^

Main.java:11: error: lambda expression not expected here

exponentiator = (int runningResult, int binLength, int binInt, int expBase) -> {
^

Main.java:23: error: cannot find symbol

exponentiator(b, length, nBinInt, b);
^

I have no explanation for these errors, can anyone help me out?

Code:

class Main {
  public static void main(String[] args) {
    fastExp(2, 13);
  }
  //This is the algorithm itself
  public static int fastExp(int b, int n) {
    //converts n (b^n) to binary for algorithm
    String nBinStr = Integer.toBinaryString(n);
    int nBinInt = Integer.parseInt(nBinStr);
    int length = String.valueOf(nBinInt).length();
    exponentiator = (int runningResult, int binLength, int binInt, int expBase) -> {
      int firstDigit = Integer.parseInt(Integer.toString(binInt).substring(1, 2));
      if(binLength = 0){
        return runningResult;
      }
      else if(firstDigit = 0){
        exponentiator((runningResult * runningResult), (binLength - 1), (binInt % (int) Math.pow(10, (int) Math.log10(binInt))), expBase);
      }
      else {
      exponentiator((runningResult * runningResult * base), (binLength - 1), (binInt % (int) Math.pow(10, (int) Math.log10(binInt))), expBase);
      }
    };
    exponentiator(b, length, nBinInt, b);
  }
}

https://repl.it/@Jodastt/Fast-Exponentiation

Sweeper :

One major problem you have is that your lambda doesn't have a type. You need to give it one. I am not aware of any types in java.util.function that can represent a function taking 4 parameters, so you probably need to declare this type yourself.

The other major problem is that you are using the variable exponentiator inside its declaration, which is invalid. To work around this, you need to add a fifth parameter to your lambda, to which the lambda itself will be passed. You will then replace the recursive calls with calls to this parameter.

Let's declare the type to represent this lambda first.

interface IntQuadRecursiveFunction {
    int apply(int a, int b, int c, int d, IntQuadRecursiveFunction f);
}

And then exponentiator can be redeclared like so:

// note the type and extra parameter "f"
IntQuadRecursiveFunction exponentiator = (runningResult, binLength, binInt, expBase, f) -> {
   int firstDigit = Integer.parseInt(Integer.toString(binInt).substring(1, 2));
   if (binLength == 0) { // It's "==", not "="
       return runningResult;
   } else if (firstDigit == 0) {
        // note the word "return", which you were missing
        // also the extra argument "f"
       return f.apply((runningResult * runningResult), (binLength - 1), (binInt % (int) Math.pow(10, (int) Math.log10(binInt))), expBase, f);
   } else {
       // should be "expBase", not "base"
       return f.apply((runningResult * runningResult * expBase), (binLength - 1), (binInt % (int) Math.pow(10, (int) Math.log10(binInt))), expBase, f);
   }
};

usage:

// you are missing a return in "fastExp" as well
return exponentiator.apply(b, length, nBinInt, b, exponentiator); // note the last argument

To be honest, if I were you I would just save all this trouble and write a normal method instead:

public static int fastExp(int b, int n) {
    //converts n (b^n) to binary for algorithm
    String nBinStr = Integer.toBinaryString(n);
    int nBinInt = Integer.parseInt(nBinStr);
    int length = String.valueOf(nBinInt).length();
    return exponentiator(b, length, nBinInt, b);
}

private static int exponentiator(int runningResult, int binLength, int binInt, int expBase) {
    int firstDigit = Integer.parseInt(Integer.toString(binInt).substring(1, 2));
    if (binLength == 0) { 
        return runningResult;
    } else if (firstDigit == 0) {
        return exponentiator((runningResult * runningResult), (binLength - 1), (binInt % (int) Math.pow(10, (int) Math.log10(binInt))), expBase);
    } else {
        return exponentiator((runningResult * runningResult * expBase), (binLength - 1), (binInt % (int) Math.pow(10, (int) Math.log10(binInt))), expBase);
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326827&siteId=1