为什么模数除法(%)仅适用于整数?

时间:2011-05-23 20:57:43

标签: c++ c

我最近遇到an issue,可以使用模数除法轻松解决,但输入是浮点数:

  

给定一个周期函数(例如sin)和一个只能在周期范围内计算它的计算机函数(例如[-π,π]),创建一个可以处理任何输入的函数。

“显而易见”的解决方案如下:

#include <cmath>

float sin(float x){
    return limited_sin((x + M_PI) % (2 *M_PI) - M_PI);
}

为什么这不起作用?我收到这个错误:

 
error: invalid operands of types double and double to binary operator %

有趣的是,它在Python中有效:

 
def sin(x):
    return limited_sin((x + math.pi) % (2 * math.pi) - math.pi)

9 个答案:

答案 0 :(得分:72)

因为“余数”的正常数学概念仅适用于整数除法。即产生整数商所需的除法。

为了将“余数”的概念扩展为实数,您必须引入一种新的“混合”运算,它将为实际操作数生成整数商。 Core C语言不支持此类操作,但它作为标准库fmod函数提供,以及C99中的remainder函数。 (请注意,这些函数不一样,并且有一些特殊性。特别是,它们不遵循整数除法的舍入规则。)

答案 1 :(得分:47)

您正在寻找fmod()

我想更具体地回答你的问题,在较旧的语言中,%运算符只是定义为整数模块划分,而在较新的语言中,他们决定扩展运算符的定义。

编辑:如果我打算猜测为什么,我会说这是因为模数运算的思想起源于数论并专门处理整数。

答案 2 :(得分:15)

我不能说确定,但我猜它主要是历史性的。相当多的早期C编译器根本不支持浮点数。它是在稍后添加的,甚至不是完全添加的 - 主要是添加了数据类型,并且语言中支持大多数原语操作,但其他一切都留给了标准库。

答案 3 :(得分:12)

C和C ++中的模运算符%是针对两个整数定义的,但有一个fmod()函数可用于双精度。

答案 4 :(得分:7)

约束在标准中:

C11(ISO / IEC 9899:201x)§6.5.5乘法运算符

  

每个操作数都应具有算术类型。 %运算符的操作数应该是   有整数类型。

C ++ 11(ISO / IEC 14882:2011)§5.6乘法运算符

  

*和/的操作数应具有算术或枚举类型; %的操作数应具有整数或枚举   类型。通常的算术转换是在操作数上执行的,并确定结果的类型。

解决方案是使用fmod,这正是%的操作数首先限于整数类型的原因,根据C99 Rationale§6.5.5乘法运算符

  

C89委员会拒绝延长%运营商以处理浮动类型,因为此类使用会复制fmod提供的设施

答案 5 :(得分:4)

尝试fmod

答案 6 :(得分:2)

%运算符为您提供数字的REMAINDER(模数的另一个名称)。对于C / C ++,这仅针对整数运算定义。 Python有点宽泛,允许你得到浮点数的余数,剩余的数字可以被分成多少次:

>>> 4 % math.pi
0.85840734641020688
>>> 4 - math.pi
0.85840734641020688
>>> 

答案 7 :(得分:2)

当您尝试查找属于%Float类型的两个数字的剩余部分时,Double运算符在C ++中不起作用。

因此,您可以尝试使用fmod / math.h中的cmath.h函数,或者您可以使用这些代码行来避免使用该头文件:

float sin(float x) {
 float temp;
 temp = (x + M_PI) / ((2 *M_PI) - M_PI);
 return limited_sin((x + M_PI) - ((2 *M_PI) - M_PI) * temp ));

}

答案 8 :(得分:0)

“模运算的数学概念适用于浮点 价值观,这也是Donald Knuth的第一个问题 在他的经典著作《计算机编程的艺术》(第一卷)中进行了讨论。 即曾经是基础知识。”

浮点模运算符定义如下:

m = num - iquot*den ; where iquot = int( num/den )

如所示,浮点数上的%运算符的无操作出现 与标准相关。 CRTL提供“ fmod”,通常是“剩余” 以及对fp编号执行%。这两个谎言的区别 他们如何处理中间的“ iquot”取整。

'remainder'使用最近舍入法,'fmod'使用简单的截断法。

如果您编写自己的C ++数字类,没有什么可以阻止您 通过包括重载运算符%来修改无操作传统。

最好的问候