为什么模分(%)只能用整数工作?

我最近遇到了一个问题 ,可以很容易地解决使用模数除法,但输入是一个浮点数:

给定一个周期函数(例如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) 

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

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

你正在寻找fmod() 。

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

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

我不能肯定地说,但我猜这主要是历史的。 不少早期的C编译器根本不支持浮点运算。 它后来被添加了,甚至不是完全的 – 大部分是数据类型被添加的,并且是语言中支持的原始的操作,但其他的一切都留给了标准库。

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

约束在标准中:

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

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

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

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

解决的办法是使用fmod ,这正是为什么%的操作数首先被限制为整数类型的原因,根据C99理论根据§6.5.5 乘法运算符

C89委员会拒绝延长运营商的浮动类型的工作,因为这样的使用将复制fmod提供的设施

尝试fmod

%运算符为您提供一个REMAINDER(模数的另一个名称)。 对于C / C ++,这只是为整数操作定义的。 Python有一点宽泛,可以让你得到浮点数的其余部分,剩下的次数可以分成多少次:

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

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

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

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

}