Computing probability of sentence using N-grams
The $N$-gram model assumes a generative model in which the next word generated depends only on the preceding $N-1$ words. Using Bayes' law, we get that the probability of a sentence $w_1,\ldots,w_n$ is
$$
P(w_1\cdots w_n) = P(w_1) P(w_2|w_1) P(w_3|w_1w_2) \cdots P(w_N|w_1\ldots w_{N-1}) P(w_{N+1}|w_2\ldots w_N) \cdots P(w_n | w_{n-N+1}\ldots w_{n-1}).
$$
In the particular cases $N=1,2,3$, this gives
$$
P(w_1\cdots w_n) = P(w_1) P(w_2) \cdots P(w_n), \\
P(w_1\cdots w_n) = P(w_1) P(w_2|w_1) P(w_3|w_2) \cdots P(w_n|w_{n-1}), \\
P(w_1\cdots w_n) = P(w_1) P(w_2|w_1) P(w_3|w_1w_2) P(w_4|w_2w_3) \cdots P(w_n|w_{n-2}w_{n-1}).
$$
This means that your expression for $N=2$ is wrong.

In practice, we don't want to store special tables for the first $N-1$ characters. There are two ways around this. First, we can ignore entirely the first $N-1$ words. This makes sense when the text is very long, and we don't expect the first few words to make a big difference in the resulting probability. Second, we can include a special "blank" symbol and add it to our tables, so that (for example) $P(w_1)$ is stored as $P(w_1|\not{b}\ldots \not{b})$.

Usually one stores not the actual probabilities but rather their logarithm. The reason is that adding numbers is faster than multiplying them. As an added benefit, you don't have to worry about the dynamic range of the floating point data type you use (the actual probability could be rather close to 0 and could cause underflow, but this is unlikely for its logarithm).

Another thing to keep in mind is that the results are more meaningful as the text becomes longer. Your example is very short and doesn't serve as a good test case.