【问题标题】:Modular operation (%) provides false output模块化操作 (%) 提供错误输出
【发布时间】:2020-11-01 13:36:15
【问题描述】:

使用函数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。

【问题讨论】:

  • 您的 c++ 概念有点不清楚。当前索引在您的情况下为 3(array[currentIdx] => array[3]) 将给出元素-4。你的问题也有点不清楚。让我知道您的输入和输出。
  • %operator 对负数有点奇怪,请参阅 stackoverflow.com/questions/11720656/… 在使用 % 解决问题之前将您的数字设为正数
  • @AlanBirtles,使用负数很好(对某些人来说有点奇怪,真的,但它仍然很好)。这里的问题是整数类型的混合。
  • 我们在过去 2 周内遇到过这个问题大约 6 次

标签: c++ modular-arithmetic


【解决方案1】:

模数运算符向零舍入(即使对于负数)。您的数学期望模数向负或正无穷大方向舍入。见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;
}

【讨论】:

  • 感谢您编辑我的代码和答案,比尔。你的回答很有用。
  • 模运算中没有四舍五入。对于最初使用% 运算符的人来说,这三个问题示例的链接可能看起来很奇怪,但结果在逻辑上仍然是正确的。 OP 发布的问题是运算符返回逻辑错误的示例(不存在 n 整数,因此 nextIdx + n* 6 = 5)。
【解决方案2】:

关于示例代码应该考虑的另一个问题是发生类型转换。由于 array.size()(6) 的类型是 size_t 而另一方面另一个数字是负数,所以编译器将负数转换为 size_t 然后对它们应用模运算符。例如 (-1)% 6 的输出是 (-1) 但 (-1) % array.size() 的输出是 (3) 因为 (-1) 转换为 size_t 并变为 (4294967295)(基于在平台上输出应该是不同的)所以(4294967295 % 6)的模数是(3)。

【讨论】:

    【解决方案3】:

    % 运算符中使用否定参数很好。问题是你混合了整数类型: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());
    }
    

    【讨论】:

      猜你喜欢
      • 2019-06-25
      • 2014-12-22
      • 2015-07-06
      • 2021-07-19
      • 1970-01-01
      • 1970-01-01
      • 2016-12-10
      • 1970-01-01
      • 2022-11-25
      相关资源
      最近更新 更多