patternjavaMinor
BF Interpreter, Follow-up: ++;++; is now +=2;
Viewed 0 times
interpreternowfollow
Problem
Follow-up to: Brainfuck Interpreter: Slower than a Snail?
Many improvements have been added, including:
I have no idea how to use JUnit to test on the output, so I stuck with Main.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
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
you should have
I don't think that
Optimization
Eliminating comments would likely help in some cases. Defining the constant
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
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.