The algorithm swaps two elements that are on equal distance from both ends of the array. The number of operations needed is number_of_operations = number_of_elements / number_elements_operated_on and since it's doing two elements at once, that's number_of_elements / 2. And hence the reason to use arr.length / 2 as the limit of the for loop. Here is a representation of what happens.
Given an array [1, 2, 3, 4, 5, 6] then array.length is 6 and the following operations are performed:
//loop i = 0, 0 < 3 == true, execute
[1, 2, 3, 4, 5, 6] -> [6, 2, 3, 4, 5, 1]
^--------------^ ^--------------^
//loop i = 1, 1 < 3 == true, execute
[6, 2, 3, 4, 5, 1] -> [6, 5, 3, 4, 2, 1]
^--------^ ^--------^
//loop i = 2, 2 < 3 == true, execute
[6, 5, 3, 4, 2, 1] -> [6, 5, 4, 3, 2, 1]
^--^ ^--^
//i = 3, 3 < 3 == false, loop stops
This works perfectly fine with odd number of elements, since there is going to just be one element in middle when you get to it.
Given an array [1, 2, 3, 4, 5] then array.length is 5 and the following operations are performed:
//loop i = 0, 0 < 2.5 == true, execute
[1, 2, 3, 4, 5] -> [5, 2, 3, 4, 1]
^-----------^ ^-----------^
//loop i = 1, 1 < 2.5 == true, execute
[5, 2, 3, 4, 1] -> [5, 4, 3, 2, 1]
^-----^ ^-----^
//loop i = 2, 2 < 2.5 == true, execute
[5, 2, 3, 4, 1] -> [5, 4, 3, 2, 1]
^ ^
//i = 3, 3 < 2.5 == false, loop stops
forloop stops. Are you familiar withforloops or is it just this algorithm which is not clear?