Fastest way to solve chain-calculations

后端 未结 5 820
长发绾君心
长发绾君心 2021-02-04 07:14

I have a input like

string input = \"14 + 2 * 32 / 60 + 43 - 7 + 3 - 1 + 0 * 7 + 87 - 32 / 34\"; 
// up to 10MB string size

int result = Calc(input); // 11
         


        
5条回答
  •  一向
    一向 (楼主)
    2021-02-04 07:29

    Here is a Java fun fact. I implemented the same thing in Java and it runs about 20 times faster than Mirai Mann implementation in C#. On my machine 100M chars input string took about 353 milliseconds.

    Below is the code that creates and tests the result.

    Also, note that while it's a good Java/C# performance tester this is not an optimal solution. A better performance can be achieved by multithreading it. It's possible to calculate portions of the string and then combine the result.

    public class Test {
    
        public static void main(String...args){
            new Test().run();
        }
    
        private void run() {
            long startTime = System.currentTimeMillis();
            Random random = new Random(123);
            int result = 0;
            StringBuilder input = new StringBuilder();
            input.append(random.nextInt(99) + 1);
            while (input.length() < 100_000_000){
                int value = random.nextInt(100);
                switch (random.nextInt(4)){
                    case 0:
                        input.append("-");
                        result -= value;
                        break;
                    case 1: // +
                        input.append("+");
                        result += value;
                        break;
                    case 2:
                        input.append("*");
                        result *= value;
                        break;
                    case 3:
                        input.append("/");
                        while (value == 0){
                            value = random.nextInt(100);
                        }
                        result /= value;
                        break;
                }
                input.append(value);
            }
            String inputData = input.toString();
            System.out.println("Test created in " + (System.currentTimeMillis() - startTime));
    
            startTime = System.currentTimeMillis();
            int testResult = test(inputData);
            System.out.println("Completed in " + (System.currentTimeMillis() - startTime));
    
            if(result != testResult){
                throw new Error("Oops");
            }
        }
    
        private int test(String inputData) {
            char[] input;
            try {
                Field val = String.class.getDeclaredField("value");
                val.setAccessible(true);
                input = (char[]) val.get(inputData);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new Error(e);
            }
            int result = 0;
            int startingI = 1;
            {
                char c = input[0];
                if (c >= '0' && c <= '9') {
                    result += c - '0';
                    c = input[1];
                    if (c >= '0' && c <= '9') {
                        result += (c - '0') * 10;
                        startingI++;
                    }
                }
            }
    
            for (int i = startingI, length = input.length, value=0; i < length; i++) {
                char operation = input[i];
                i++;
                char c = input[i];
                if(c >= '0' && c <= '9'){
                    value += c - '0';
                    c = input[i + 1];
                    if(c >= '0' && c <= '9'){
                        value = value * 10 + (c - '0');
                        i++;
                    }
                }
                switch (operation){
                    case '-':
                        result -= value;
                        break;
                    case '+':
                        result += value;
                        break;
                    case '*':
                        result *= value;
                        break;
                    case '/':
                        result /= value;
                        break;
                }
                value = 0;
            }
    
            return result;
        }
    }
    

    When you read the code then you can see that I used a small hack when converting the string to a char array. I mutated the string in order to avoid additional memory allocations for the char array.

提交回复
热议问题