HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

BF Interpreter, Follow-up: ++;++; is now +=2;

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
interpreternowfollow

Problem

Follow-up to: Brainfuck Interpreter: Slower than a Snail?

Many improvements have been added, including:

  • Remembering where the matching [ and ] is



  • Combining +s, -s, `s into groups



  • Providing the option to not optimize the code



I have no idea how to use JUnit to test on the output, so I stuck with
Main.java:

public class Main {

    public static void main(String[] args) throws InterruptedException {
        BFCode code = new BFCode(
                "++++++++++[>++++++++++>++++++++++>->>>>>>>>>>-->+++++++[->++++++++++[->+>+>+>+>+++>>>++++++++[->>]+++++[->]>-->++++++[->+++++++++++[->+>+>+>+>+>++++++>++++++>++++++++[->>]++++++[->>]>-->---+[->>+>++[-->++]-->+++[---+>-[]]>++[--+[->[-]+++++[---->++++]-->[->+>[.>]>++]-->+++]---+[->-[+>+++++++++++>-[>+>>]>[+[-]>+>>]>[-]>>>++++++++++->+[-]>[++++++++.[-]]]]]<<<.<]");
        long time = System.nanoTime();
        BFInterpreter.interpret(code);
        System.out.println((System.nanoTime() - time) + '\n');
        Thread.sleep(1000);
        time = System.nanoTime();
        BFInterpreter.interpretNoOptimizations(code);
        System.out.println(System.nanoTime() - time);
    }

}


The
Thread.sleep(1000) is there for me to see a quick result before moving on to the next test.

Output:

1
2
Fizz
...
98
Fizz
Buzz
39662432

1
2
...
98
Fizz
Buzz
26999614


As the code for Fizzbuzz is already optimized, it is unnecessary to optimize it again. If it were to include a bunch of extra
+- and <> groups though, the results would be different.

As you can see, though, even the optimize-and-run method ran about twice as fast as the previous post.

BFInterpreter.java

``
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class BFInterpreter {

public static final int BF_MEMORY_SIZE = 30000;

private static final InputStreamReader INPUT = new InputStreamReader(System.in);

private static final in

Solution

Object-oriented design

As before, you are not using interfaces effectively. When two pieces of code serve the same role, then they should implement the same interface. Instead of

public class BFInterpreter {
    public static void interpretNoOptimizations(BFCode code) { … }
    public static void interpret(BFCode code) { … }
}


you should have

public interface BFInterpreter {  // or class, or abstract class
    void interpret(BFCode code);
}

public class NaiveBFInterpreter implements BFInterpreter {
    @Override
    public void interpret(BFCode code) { … }
}

public class OptimizingBFInterpreter implements BFInterpreter {
    @Override
    public void interpret(BFCode code) { … }
}


I don't think that BFCode.getOptimizedCode() is necessary. Just call BFOptimizer.optimize(…) directly instead. Then, the BFCode class is nothing more than a glorified String, so you might as well eliminate it in favour of using String directly. (But read on…)

Optimization

Eliminating comments would likely help in some cases. Defining the constant public static final String EMPTY_STRING = ""; is just silly, though.

Eliminating pairs of mutually cancelling operations is a pretty weak optimization. It would only have an effect on code that was deliberately pessimized in the first place, which would be unlikely.

What would actually make a difference to performance is JITting the code: building jump tables and coalescing consecutive +/-/` operations so that you don't have to execute while loops like this within interpret():

case '+':
    times = 1;
    while (commands[++i] == '+') {
        times++;
    }
    i--;
    bfMemory[pointer] += times;
    break;


To do that, you'll need
BFCode to use a richer representation than just a String`.

Code Snippets

public class BFInterpreter {
    public static void interpretNoOptimizations(BFCode code) { … }
    public static void interpret(BFCode code) { … }
}
public interface BFInterpreter {  // or class, or abstract class
    void interpret(BFCode code);
}

public class NaiveBFInterpreter implements BFInterpreter {
    @Override
    public void interpret(BFCode code) { … }
}

public class OptimizingBFInterpreter implements BFInterpreter {
    @Override
    public void interpret(BFCode code) { … }
}
case '+':
    times = 1;
    while (commands[++i] == '+') {
        times++;
    }
    i--;
    bfMemory[pointer] += times;
    break;

Context

StackExchange Code Review Q#111975, answer score: 5

Revisions (0)

No revisions yet.