Data::Dumper is a good tool to explore what is going on here. It makes it easy to visualise your data structures.
If we run your code and then display @f using Data::Dumper, we get this:
$VAR1 = [
2,
3,
3,
4,
4,
5,
5,
6,
6,
[ ... snip ... ]
40,
40,
41,
41,
42,
42,
43
];
So that's not doing what you want. If you push an array onto another array then Perl just adds each element from the second array to the end of the first array. It becomes impossible to tell which element belongs to which array. This is known as "array flattening".
It happens because an element in an array can only hold a single scalar value. And another array is not a scalar value. But we can take a reference to an array and that is then a scalar value. You get a reference to an array using \.
The change to your code is simple:
my @e=($i+=2, $i+1); # declare @e inside the loop
push(@f,\@e); # Take a reference
And the output we now get is:
$VAR1 = [
[
2,
3
],
[
3,
4
],
[
4,
5
],
[ ... snip ... ]
[
39,
40
],
[
40,
41
],
[
41,
42
],
[
42,
43
]
];
You can clearly see the individual "sub-arrays" inside your main array.
There's more about this in the perllol manual page and you can find out far more about references in perlreftut and perlref.