81
votes

I recently ran into an issue that could easily be solved using modulus division, but the input was a float:

Given a periodic function (e.g. sin) and a computer function that can only compute it within the period range (e.g. [-π, π]), make a function that can handle any input.

The "obvious" solution is something like:

#include <cmath>

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

Why doesn't this work? I get this error:

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

Interestingly, it does work in Python:

def sin(x):
    return limited_sin((x + math.pi) % (2 * math.pi) - math.pi)
9
π is not equal to 3.14, and in fact its not representable as any floating point type. Computing sin(x) for large values of x actually requires a very difficult transcendental argument reduction process that cannot get by with any finite approximation of pi. - R.. GitHub STOP HELPING ICE
This is almost certainly a homework assignment, so floating point errors are either outside the scope of the assignment, or this is meant to lead to a discussion of more rigorous numerical analysis. Either way, fmod is likely what the instructor is looking for. - Dennis Zickefoose
It's not homework, it's just something that came up while reading another SO question (stackoverflow.com/questions/6091837/…) - Brendan Long
OK, I should have been more precise in my statement. My point was that if the argument can grow unboundedly large (not just double precision exponent size), no finite approximation of pi will suffice. For double, yes, a very very long approximation of pi will suffice. - R.. GitHub STOP HELPING ICE
@aschepler: I don't think you understood the issue. - R.. GitHub STOP HELPING ICE

9 Answers

78
votes

Because the normal mathematical notion of "remainder" is only applicable to integer division. i.e. division that is required to generate integer quotient.

In order to extend the concept of "remainder" to real numbers you have to introduce a new kind of "hybrid" operation that would generate integer quotient for real operands. Core C language does not support such operation, but it is provided as a standard library fmod function, as well as remainder function in C99. (Note that these functions are not the same and have some peculiarities. In particular, they do not follow the rounding rules of integer division.)

54
votes

You're looking for fmod().

I guess to more specifically answer your question, in older languages the % operator was just defined as integer modular division and in newer languages they decided to expand the definition of the operator.

EDIT: If I were to wager a guess why, I would say it's because the idea of modular arithmetic originates in number theory and deals specifically with integers.

18
votes

I can't really say for sure, but I'd guess it's mostly historical. Quite a few early C compilers didn't support floating point at all. It was added on later, and even then not as completely -- mostly the data type was added, and the most primitive operations supported in the language, but everything else left to the standard library.

12
votes

The modulo operator % in C and C++ is defined for two integers, however, there is an fmod() function available for usage with doubles.

7
votes

The constraints are in the standards:

C11(ISO/IEC 9899:201x) §6.5.5 Multiplicative operators

Each of the operands shall have arithmetic type. The operands of the % operator shall have integer type.

C++11(ISO/IEC 14882:2011) §5.6 Multiplicative operators

The operands of * and / shall have arithmetic or enumeration type; the operands of % shall have integral or enumeration type. The usual arithmetic conversions are performed on the operands and determine the type of the result.

The solution is to use fmod, which is exactly why the operands of % are limited to integer type in the first place, according to C99 Rationale §6.5.5 Multiplicative operators:

The C89 Committee rejected extending the % operator to work on floating types as such usage would duplicate the facility provided by fmod

3
votes
2
votes

The % operator gives you a REMAINDER(another name for modulus) of a number. For C/C++, this is only defined for integer operations. Python is a little broader and allows you to get the remainder of a floating point number for the remainder of how many times number can be divided into it:

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

The % operator does not work in C++, when you are trying to find the remainder of two numbers which are both of the type Float or Double.

Hence you could try using the fmod function from math.h / cmath.h or you could use these lines of code to avoid using that header file:

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

}

1
votes

"The mathematical notion of modulo arithmetic works for floating point values as well, and this is one of the first issues that Donald Knuth discusses in his classic The Art of Computer Programming (volume I). I.e. it was once basic knowledge."

The floating point modulus operator is defined as follows:

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

As indicated, the no-op of the % operator on floating point numbers appears to be standards related. The CRTL provides 'fmod', and usually 'remainder' as well, to perform % on fp numbers. The difference between these two lies in how they handle the intermediate 'iquot' rounding.

'remainder' uses round-to-nearest, and 'fmod' uses simple truncate.

If you write your own C++ numerical classes, nothing prevents you from amending the no-op legacy, by including an overloaded operator %.

Best Regards