Modular opertation (%) provides false output

百般思念 提交于 2020-07-15 08:20:40

问题


With a function, getNextIdx, I want to receive a new index for an array that depends on the current index and the value of the array at that index.

I want the function to return the new index by summing the current index with the value of the array at that index, modular to the array size.

#include<vector> 
using namespace std;

int getNextIdx(int currentIdx, vector<int> array) {
    int jump = array[currentIdx];
    int nextIdx = (currentIdx + jump) % array.size();
    
    return (nextIdx >= 0) ? nextIdx : nextIdx + array.size();
}
int main() {
    vector<int> test = {2, 3, 1, -4, -4, 2};
    int nextIdx = getNextIdx(3, test);    
} 

Example: If the current index is 3 (4th element), and the value of the 4th element in the array is -4, and the size of the array is 6, then the function should return 5.

The problem is that my program returns 3 in the above example.


回答1:


The modulus operator rounds towards zero (even for negative numbers). Your math expects modulus to round towards negative or positive infinity. See Modulo operation with negative numbers

int getNextIdx(int currentIdx, vector<int> array){
  int jump = array[currentIdx];
  int nextIdx = currentIdx + jump;
  if (nextIdx < 0)
    nextIdx += array.size();
  if (nextIdx >= array.size())
    nextIdx -= array.size();
  return nextIdx;
}



回答2:


Another issue that should be considered about the sample code is type casting take place. Since type of array.size()(6) is size_t and on other hand the other number is negative so compiler cast the negative number to size_t and then apply the Modulo operator on them. For example the output of (-1)% 6 is (-1) but the out put of (-1) % array.size() is (3) because (-1) convert to size_t and became (4294967295)(based on platform the output should be varied) so the Modulo of (4294967295 % 6) is (3).




回答3:


Using negative arguments with the % operator is fine. The problem is that you're mixing integer types: nextIdx is a singed integer and array.size() returns an unsigned integer. So your problem can be boiled down to this line of code:

std::cout << -1 % 6u << std::endl; // returns 3

What the % operation does here is convert the type of the left-hand-side to the type of the right-hand-side, so your -1 becomes unsigned, and this messes with your logical modular operation.

You could solve this by changing your function like so:

int nextIdx = (currentIdx + jump) % (int) array.size();

(unasked for) CODE REVIEW:

It would be even better if you could arrange your functions to do these kinds of type conversions for you by defining their inputs appropriately. Also, let's sanitise the inputs.

Something like this:

#include <cassert>
#include <iostream>
#include <vector> 

int64_t PostiveModular (int64_t n, int64_t m)
{
    assert(m > 0);
    
    return n % m + (n < 0) * m;
}

uint64_t NextIndex (uint64_t i, const std::vector<int> & vec)
{
    assert(i < vec.size());
    
    return PostiveModular(i + vec[i], vec.size());
}


来源:https://stackoverflow.com/questions/62857523/modular-opertation-provides-false-output

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!