Bad documentation
I did Advent of Code day one in Fortran and found myself in want of a shift function. Fortunately for me, Fortran offers the CSHIFT function which does what I want.
Here is the documentation
Synopsis:
RESULT = CSHIFT(ARRAY, SHIFT [, DIM])
Description:
CSHIFT(ARRAY, SHIFT [, DIM]) performs a circular shift on elements of ARRAY along the dimension of DIM. If DIM is omitted it is taken to be 1. DIM is a scalar of type INTEGER in the range of 1 \leq DIM \leq n) where n is the rank of ARRAY. If the rank of ARRAY is one, then all elements of ARRAY are shifted by SHIFT places. If rank is greater than one, then all complete rank one sections of ARRAY along the given dimension are shifted. Elements shifted out one end of each rank one section are shifted back in the other end.
Class:
Transformational function
Arguments:
ARRAY Shall be an array of any type.
SHIFT The type shall be INTEGER.
DIM The type shall be INTEGER.
Notes:
ARRAY can also be UNSIGNED.
Return value:
Returns an array of same type and rank as the ARRAY argument.
Example:
program test_cshift
integer, dimension(3,3) :: a
a = reshape( (/ 1, 2, 3, 4, 5, 6, 7, 8, 9 /), (/ 3, 3 /))
print '(3i3)', a(1,:)
print '(3i3)', a(2,:)
print '(3i3)', a(3,:)
a = cshift(a, SHIFT=(/1, 2, -1/), DIM=2)
print *
print '(3i3)', a(1,:)
print '(3i3)', a(2,:)
print '(3i3)', a(3,:)
end program test_cshift
This is awful: after reading the documentation, it’s still not clear
what this function actually does. For example, I still don’t know what
the result of cshift((/1, 2, 3/), 1) is. Is it
2 3 1 (left shift, like std::rotate) or
is it 3 1 2 (right shift, like
numpy.roll)?
Compare this to a snippet from the cppreference documentation for
std::rotate
1) Performs a left rotation on a range of elements.
Specifically, std::rotate swaps the elements in the range [first, last) in such a way that the elements in [first, middle) are placed after the elements in [middle, last) while the orders of the elements in both ranges are preserved.
It even gives an example implementation to makes it clear what the functoin does
template<class ForwardIt>
constexpr // since C++20
ForwardIt rotate(ForwardIt first, ForwardIt middle, ForwardIt last)
{
if (first == middle)
return last;
if (middle == last)
return first;
ForwardIt write = first;
ForwardIt next_read = first; // read position for when “read” hits “last”
for (ForwardIt read = middle; read != last; ++write, ++read)
{
if (write == next_read)
next_read = read; // track where “first” went
std::iter_swap(write, read);
}
// rotate the remaining sequence into place
rotate(write, next_read, last);
return write;
}
It also gives example usage and output!
#include <algorithm>
#include <iostream>
#include <vector>
auto print = [](const auto remark, const auto& v)
{
std::cout << remark;
for (auto n : v)
std::cout << n << ' ';
std::cout << '\n';
};
int main()
{
std::vector<int> v{2, 4, 2, 0, 5, 10, 7, 3, 7, 1};
print("before sort:\t\t", v);
// insertion sort
for (auto i = v.begin(); i != v.end(); ++i)
std::rotate(std::upper_bound(v.begin(), i, *i), i, i + 1);
print("after sort:\t\t", v);
// simple rotation to the left
std::rotate(v.begin(), v.begin() + 1, v.end());
print("simple rotate left:\t", v);
// simple rotation to the right
std::rotate(v.rbegin(), v.rbegin() + 1, v.rend());
print("simple rotate right:\t", v);
}
before sort: 2 4 2 0 5 10 7 3 7 1
after sort: 0 1 2 2 3 4 5 7 7 10
simple rotate left: 1 2 2 3 4 5 7 7 10 0
simple rotate right: 0 1 2 2 3 4 5 7 7 10
The CSHIFT documentation contains a 2-dimensional shift example (not simple!) and contains no output to explain what the code does.
If it’s not clear I’m salty I guessed the wrong behaviour for CSHIFT