It seems that the following programs do more or less the same and they don't really differ. But that is not true.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )); do s=$((s+1)) done echo "$s"
This is the correct way to implement this. The expression s+1 is evaluated by the shell and can be assigned to a variable.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )); do s=`expr "$s" + 1` done echo "$s"
Here the expression will be calculated by the program expr, which isn't a shell builtin but an external Unix program. So instead of simply adding 1 and s a program must be started und its output must be read and written to the variable. Starting a programm needs a lot of resources and a lot of time. And this program is run 1000000 times. So the program will be much slower than the previous. Nevertheless the code works correctly.
#!/bin/bash -e s=-1000 for (( i=0; i<1000000; i++ )); do ((s=s+1)) done echo "$s"
If the -e flag isn't set, the program will work correctly, too. But if -e is set when s=-1 and ((s=s+1)) is calculated. The expression s=s+1 evaluates to 0 and the exit code of ((0)) is >0 which is interpreted as an error by the shell and the shell exits the program.
The reason to set the -e flag is that it is the simplest way of error processing: stop if an error ocurrs.