This is due to the type of v.size(), which is an unsigned type. Due to integer promotion, this means that the result will also be treated as unsigned, despite i being a signed type.
I am assuming you are compiling on 64 bit. This means that in addition to promotion to unsigned, the result will also be of the 64 bit type unsigned long long. Step by step:
unsigned long long _i = (unsigned long long)-4; // 0xFFFFFFFFFFFFFFFC!
unsigned long long result = _i % (unsigned long long)7; // 5
Since presumably you want to preserve the signedness of i, in this case it is enough to cast v.size() to a signed type to prevent the promotion to unsigned:
i % (int)v.size() will give -4.