如何在处理负数的 C/C++/Obj-C 中编写模 (%) 运算符

新手上路,请多包涵

我最讨厌 C 派生语言(作为数学家)之一是

(-1) % 8 // comes out as -1, and not 7

fmodf(-1,8) // fails similarly

最好的解决方案是什么?

C++ 允许模板和运算符重载的可能性,但对我来说,这两者都是浑水。收到的例子很感激。

原文由 P i 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 465
2 个回答

首先,我想指出,您甚至不能依赖 (-1) % 8 == -1 的事实。您唯一可以依靠的是 (x / y) * y + ( x % y) == x 。但是,余数是否为负是 _实现定义的_。

参考:C++03 第 5.6 段第 4 条:

二元 / 运算符产生商,二元 % 运算符产生第一个表达式除以第二个表达式的余数。如果 / 或 % 的第二个操作数为零,则行为未定义;否则 (a/b)*b + a%b 等于 a。如果两个操作数都是非负数,则余数是非负数; 如果不是,则余数的符号是 implementation-defined

这里它遵循一个处理两个负操作数的版本,以便从 除数 中减去 数的结果可以从 被除数 中减去,因此它将是实际除法的 _下限_。 mod(-1,8) 结果为 7,而 mod(13, -8) 为 -3。

 int mod(int a, int b)
{
   if(b < 0) //you can check for b == 0 separately and do what you want
     return -mod(-a, -b);
   int ret = a % b;
   if(ret < 0)
     ret+=b;
   return ret;
}

原文由 Armen Tsirunyan 发布,翻译遵循 CC BY-SA 4.0 许可协议

对于不使用分支且仅使用 1 个 mod 的解决方案,您可以执行以下操作

// Works for other sizes too,
// assuming you change 63 to the appropriate value
int64_t mod(int64_t x, int64_t div) {
  return (x % div) + (((x >> 63) ^ (div >> 63)) & div);
}

原文由 Kyle Butt 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题