Модульная работа (%) дает ложный вывод - PullRequest
3 голосов
/ 12 июля 2020

С помощью функции getNextIdx я хочу получить новый индекс для массива, который зависит от текущего индекса и значения массива в этом индексе.

Я хочу, чтобы функция возвращала новый индекс путем суммирования текущего индекса со значением массива в этом индексе, модульным по размеру массива.

#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);    
} 

Пример: Если текущий индекс равен 3 (4-й элемент), и значение 4-й элемент в массиве равен -4, а размер массива равен 6, тогда функция должна вернуть 5.

Проблема в том, что моя программа возвращает 3 в приведенном выше примере.

Ответы [ 3 ]

3 голосов
/ 12 июля 2020

Еще одна проблема, которую следует учитывать в примере кода, - это приведение типов. Поскольку тип array.size () (6) равен size_t, а с другой стороны, другое число отрицательно, компилятор преобразовал отрицательное число в size_t, а затем применил к ним оператор Modulo. Например, результат (-1)% 6 равен (-1), но результат (-1)% array.size () равен (3), потому что (-1) преобразуется в size_t и становится (4294967295) (на основе на платформе вывод должен быть изменен), поэтому модуль (4294967295% 6) равен (3).

1 голос
/ 12 июля 2020

Использование отрицательных аргументов с оператором % нормально. Проблема в том, что вы смешиваете целые типы: nextIdx - это целое число, а array.size() возвращает целое число без знака. Итак, ваша проблема может быть сведена к этой строке кода:

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

Здесь операция % преобразует тип левой части в тип правой части. сторона, поэтому ваш -1 становится беззнаковым, и это мешает вашей логической модульной операции.

Вы можете решить эту проблему, изменив свою функцию следующим образом:

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

(не запрашивается) ОБЗОР КОДА :

Было бы еще лучше, если бы вы могли организовать свои функции для выполнения таких преобразований типов за вас, определив их входные данные соответствующим образом. Также давайте продезинфицируем входы.

Примерно так:

#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());
}
0 голосов
/ 12 июля 2020

Оператор модуля округляет до нуля (даже для отрицательных чисел). Ваша математика ожидает, что модуль округляется в сторону отрицательной или положительной бесконечности. См. операцию по модулю с отрицательными числами

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...