Can't use modulus on doubles?
Asked Answered
I

5

244

I have a program in C++ (compiled using g++). I'm trying to apply two doubles as operands to the modulus function, but I get the following error:

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

Here's the code:

int main() {
    double x = 6.3;
    double y = 2;
    double z = x % y;
}
Inion answered 4/2, 2012 at 6:2 Comment(4)
As has been noted, fmod() provides the necessary function. As has not yet been noted, it's important to realize that rounding errors in the second operand of fmod may cause unexpected behaviors. For example, fmod(1, 0.1); should mathematically be zero, but will in fact be almost 0.1. The extent of error goes up with the magnitude of the quotient. For example, fmod(9E14, 0.1); evaluates to about 0.05, which is from a mathematical standpoint just plain wrong.Chainey
@Chainey more details would be awesome. I think have an idea of what's on behind the scenes to cause what you say to be true, but it would be good to see the reasons for why what you say is true; would be interesting to see how it works behind the scenes (I think I understand but could very easily be wrong).Skylark
Floating-point values represent exact integer multiples or fractions of powers of two. For example, the integer literal 0.1 is exactly 3602879701896397/36028797018963968 (the latter value is a power of two). fmod(x,0.1) will divide x by that precise fraction and take the remainder, rather than dividing by the numerical value "one tenth".Chainey
Possible duplicate: Why does modulus division (%) only work with integers?Freeland
C
340

The % operator is for integers. You're looking for the fmod() function.

#include <cmath>

int main()
{
    double x = 6.3;
    double y = 2.0;
    double z = std::fmod(x,y);

}
Ciceronian answered 4/2, 2012 at 6:4 Comment(5)
I am programming in C++ for Qt and fmod has a bug there. The result of fmod(angle, 360) can be 360 (WAT?!)Healall
@Paul: That's probably not a bug. If angle is, say, 359.9999999, then both angle and fmod(angle, 360) are likely to be displayed as 360. (Add more 9s as needed.) Try printing the values with, say, 50 digits of precision.Androgen
@Healall Qt's QString::format will round. If it is that critical, you will either have to round yourself or check the output for "360" and replace it with your own value.Ego
@Rohan main(void) is not necessary in C++ (it's C legacy) and your edit isn't improving anything else either. I reverted it back.Yean
This doesn't work for negative numbers. std::fmod(-1.0, 2 * M_PI) returns -1.0, I would expect approximately 5.28.Mores
H
40

fmod(x, y) is the function you use.

Hel answered 4/2, 2012 at 6:5 Comment(0)
D
8

You can implement your own modulus function to do that for you:

double dmod(double x, double y) {
    return x - (int)(x/y) * y;
}

Then you can simply use dmod(6.3, 2) to get the remainder, 0.3.

Devisal answered 1/1, 2019 at 19:20 Comment(2)
Still not a perfect solution. x=10.499999999999998, y=0.69999999999999996 returns 0.69999999999999929 instead of 0.0Cydnus
@tarpista: That's expected, with floating point numbers.Cola
S
6

Use fmod() from <cmath>. If you do not want to include the C header file:

template<typename T, typename U>
constexpr double dmod (T x, U mod)
{
    return !mod ? x : x - mod * static_cast<long long>(x / mod);
}

//Usage:
double z = dmod<double, unsigned int>(14.3, 4);
double z = dmod<long, float>(14, 4.6);
//This also works:
double z = dmod(14.7, 0.3);
double z = dmod(14.7, 0);
double z = dmod(0, 0.3f);
double z = dmod(myFirstVariable, someOtherVariable);
School answered 19/6, 2017 at 14:21 Comment(2)
Why would you not want to include the C header file? That's what it's there for.Androgen
No harm in putting the code in the answer. Thank you.Gearing
R
0

Here is a function that also works with both positive and negative numbers:

#include <cmath>

inline double nmod(double x, double y) {
    return std::fmod(std::fmod(x, y) + y, y);
}

It will always return a positive number if x is negative or positive.

Note that if y is negative, the returned value will be negative. If you need a function that will return a positive in any case, then one need to use std::fabs() on y, i.e.:

inline double nmod2(double x, double y) {
    return std::fmod(std::fmod(x, y) + std::fabs(y), y);
}
Rosenzweig answered 6/6, 2023 at 9:18 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.