Add the modulus operator to floating point types.

210 views
Skip to first unread message

ryan...@digipen.edu

unread,
Apr 24, 2018, 3:07:12 AM4/24/18
to ISO C++ Standard - Future Proposals
I think that it is discriminatory that integers have modulus operators but floats do not.
It is unacceptable, and that is my opinion.

I propose we add the modulus operator to floating point types.

Jeff Hammond

unread,
Apr 24, 2018, 3:31:29 AM4/24/18
to std-pr...@isocpp.org

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/87b7dbad-2d98-4e1a-899e-4e5342691465%40isocpp.org.



--

ryan...@digipen.edu

unread,
Apr 24, 2018, 3:47:13 AM4/24/18
to ISO C++ Standard - Future Proposals
constexpr float f = 13.f % 2.1f; // f == 0.4
constexpr float f = std::fmod(13.f, 2.1f); // not compilable


On Tuesday, April 24, 2018 at 3:31:29 PM UTC+8, Jeff Hammond wrote:
On Tue, Apr 24, 2018 at 10:07 AM, <ryan...@digipen.edu> wrote:
I think that it is discriminatory that integers have modulus operators but floats do not.
It is unacceptable, and that is my opinion.

I propose we add the modulus operator to floating point types.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

John McFarlane

unread,
Apr 24, 2018, 5:43:44 AM4/24/18
to std-pr...@isocpp.org
The remainder can be thought of as the value that is lost as a result of rounding down of the quotient. The rounding occurs because integers have a fixed resolution of 1. Floats do not.

For integer division, if n/d=q and n%d=r then if follows that q*d+r=n. So having a remainder of 0.4f in your example only makes sense if 13.f / 2.1f == 6 and that would change the behavior of floating-point division.

Message has been deleted

Tony V E

unread,
Apr 24, 2018, 6:29:36 AM4/24/18
to ISO C++ Standard - Future Proposals
Would you be equally happy if fmod was made constexpr? 
(instead of % for floats)

Sent from my BlackBerry portable Babbage Device
Sent: Tuesday, April 24, 2018 3:47 AM
To: ISO C++ Standard - Future Proposals
Subject: Re: [std-proposals] Add the modulus operator to floating point types.

dgutson .

unread,
Apr 24, 2018, 6:35:58 AM4/24/18
to std-proposals
(Same for std::remainder?)

Jeff Hammond

unread,
Apr 24, 2018, 6:43:37 AM4/24/18
to std-pr...@isocpp.org
Did you spend any time researching this topic before you posted?  The issue with your example isn't fmod but constexpr in <cmath> and the proposal to support this is linked from the top google search hit for "constexpr c++ cmath".

https://stackoverflow.com/questions/42189190/why-doesnt-the-c-standard-library-provide-constexpr-versions-of-the-cmath-fun points to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0533r0.pdf, which contains

constexpr float fmod(float x, float y); // see [library.c]
constexpr double fmod(double x, double y);
constexpr long double fmod(long double x, long double y); // see [library.c]
constexpr float fmodf(float x, float y);
constexpr long double fmodl(long double x, long double y);

To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.
Message has been deleted

ryan...@digipen.edu

unread,
Apr 24, 2018, 11:12:26 AM4/24/18
to ISO C++ Standard - Future Proposals, ryan...@digipen.edu
I presume that f is floating-point, and mod is modulo, in std::fmod.
In which case, fmod is a "function that does modulo on 2 floating-point arguments".
I propose for a floating-point modulus operator as it's behavior has already been defined in fmod as such.
Why is there a "function that does modulo on 2 floating-point arguments" but no "operator that does modulo on 2 floating-point operands"?
What's more? Other languages (like c#) have their own % float operator, having the exact same behavior as fmod from what I've read: "The returned value has the same sign as the numerator and is less than denominator in magnitude". I had to highlight the word exact because it is not surprising.

Sorry for the deleted posts.
I was not thinking clearly.

Thiago Macieira

unread,
Apr 24, 2018, 12:04:52 PM4/24/18
to std-pr...@isocpp.org
On Tuesday, 24 April 2018 08:12:26 PDT ryan...@digipen.edu wrote:
> Sorry for the deleted posts.

There's no such thing as deleted posts. Once you post, it's out here forever
and cannot be deleted.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center



John McFarlane

unread,
Apr 24, 2018, 12:27:01 PM4/24/18
to std-pr...@isocpp.org, ryan...@digipen.edu
On Tue, Apr 24, 2018 at 8:12 AM <ryan...@digipen.edu> wrote:
I presume that f is floating-point, and mod is modulo, in std::fmod.
In which case, fmod is a "function that does modulo on 2 floating-point arguments".
I propose for a floating-point modulus operator as it's behavior has already been defined in fmod as such.
Why is there a "function that does modulo on 2 floating-point arguments" but no "operator that does modulo on 2 floating-point operands"?

The short answer is going to be "because that's how C does it". If floating-point % never got added, it is likely because there is not enough demand. The cost of adding a new language feature would be considerable and the benefits would be minimal. Adding a function to the standard library is far easier and in this case, it serves much the same purpose (constexpr issues aside). As well as existing in C, integer % is far more desirable because integer / is further from the 'real' quotient (on average and for typical ranges) .

Also, integer / and % are in a sense complementary. You are asking for a % which does not complement its equivalent /. (In Python there is // which might be said to perform such a role.)

What's more? Other languages (like c#) have their own % float operator, having the exact same behavior as fmod from what I've read: "The returned value has the same sign as the numerator and is less than denominator in magnitude". I had to highlight the word exact because it is not surprising.

I was surprised to read that C# has this. Then briefly surprised by the search results when I looked for confirmation. Top results seem to be SO questions by people who are confused by the results of % when used in conjunction with decimal fractions.

John


Sorry for the deleted posts.
I was not thinking clearly.


On Tuesday, April 24, 2018 at 3:07:12 PM UTC+8, ryan...@digipen.edu wrote:
I think that it is discriminatory that integers have modulus operators but floats do not.
It is unacceptable, and that is my opinion.

I propose we add the modulus operator to floating point types.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Hyman Rosen

unread,
Apr 24, 2018, 1:45:39 PM4/24/18
to std-pr...@isocpp.org
On Tue, Apr 24, 2018 at 3:47 AM, <ryan...@digipen.edu> wrote:
constexpr float f = 13.f % 2.1f; // f == 0.4
constexpr float f = std::fmod(13.f, 2.1f); // not compilable

Actually, if we were to have a % operator for float, the result of 13.f % 2.1%f would be
 0.40000057220458984375 (given IEEE binary floating point), and would lead to whining,
whinging, and unhappiness.

That's because the thing that you write as 2.1f is, in fact, 2.099999904632568359375,
and the remainder when six of those are subtracted from thirteen is the value above.
Note that this value is not the value of the thing you write as
0.4f, which is
0.4000000059604644775390625
.

It's a different story with decimal floating-point, of course.

Bo Persson

unread,
Apr 24, 2018, 2:36:45 PM4/24/18
to std-pr...@isocpp.org
On 2018-04-24 17:12, ryan...@digipen.edu wrote:
> I presume that *f* is floating-point, and *mod* is modulo, in std::*fmod**.*
> In which case, *fmod* is a "function that does modulo on 2
> floating-point arguments".
> I propose for a floating-point modulus operator as it's behavior has
> already been defined in *fmod *as such.

Changing the language to get another way of doing something that can
already be done in a reasonable wya is likely very low priority for the
committee.

It's not like using % is extremely more convenient and going to be
useful to a wide audience.



Bo Persson




Jakob Riedle

unread,
Apr 25, 2018, 12:31:28 PM4/25/18
to ISO C++ Standard - Future Proposals
Am Dienstag, 24. April 2018 11:43:44 UTC+2 schrieb John McFarlane:
The remainder can be thought of as the value that is lost as a result of rounding down of the quotient. The rounding occurs because integers have a fixed resolution of 1. Floats do not.

For integer division, if n/d=q and n%d=r then if follows that q*d+r=n. So having a remainder of 0.4f in your example only makes sense if 13.f / 2.1f == 6 and that would change the behavior of floating-point division.

I disagree at this point. I agree that the intermediate division result is not used as a floating point value but casted to a whole number instead (which is not consistent, but very intuitive, since the operation would have no meaning otherwise as you already prescribed).
However, you can always find a system of reasoning that justifies a language inconsistency with regards to the desires of language users.
The modulo operation clearly has only one intuitive behaviour (excluded signed operands) which additionally has a significant amount of users that would benefit from such a change, regardles of whether the committee prioritises that way.

I am in favor of this change. +1

Jakob


Jake Arkinstall

unread,
Apr 25, 2018, 12:57:22 PM4/25/18
to std-pr...@isocpp.org
I'm also in favour of the change. We can talk about the uses of it and the pitfalls of floating representation until the cows come home, but that doesnt change that there are uses (justifying the existence of fmodf in the first place), that it is already deemed useful enough to be effortlessly implemented in a variety of other languages, and that the "different code for different types" ethos is not the C++ way.

Whether or not I believe that the change is feasible is another matter. I can only see three reasonable approaches. The first is to get the C community on board. Failing that, we could figure out a way of allowing operator functions on primitives without demolishing the language. Failing that, we could standardise a wrapping class around certain primitives that allows us to embellish them without the negotiations required for the previous two approaches.

These are in descending order of usefulness but ascending order of ease. 

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Hyman Rosen

unread,
Apr 25, 2018, 1:09:54 PM4/25/18
to std-pr...@isocpp.org
On Wed, Apr 25, 2018 at 12:31 PM, Jakob Riedle <jakob....@gmail.com> wrote:
The modulo operation clearly has only one intuitive behaviour

As I said before, if floating-point % existed, then 13.0f % 2.6f would result in
0.40000057220458984375f exactly.  The values written as 0.40000056f,
0.40000057f, and 0.40000058f all convert to that value, but the value written
as 0.4f does not, being exactly equal to 0.4000000059604644775390625f.

This is not at all intuitive, even before you get to compiler permission to keep
expression results in extended precision.  Making an operator that fools people
is going to make them unhappy.

Jake Arkinstall

unread,
Apr 25, 2018, 1:17:37 PM4/25/18
to std-pr...@isocpp.org
On Wed, 25 Apr 2018, 18:09 Hyman Rosen, <hyman...@gmail.com> wrote:
On Wed, Apr 25, 2018 at 12:31 PM, Jakob Riedle <jakob....@gmail.com> wrote:
The modulo operation clearly has only one intuitive behaviour

As I said before, if floating-point % existed, then 13.0f % 2.6f would result in
0.40000057220458984375f exactly.  The values written as 0.40000056f,
0.40000057f, and 0.40000058f all convert to that value, but the value written
as 0.4f does not, being exactly equal to 0.4000000059604644775390625f.

This is not at all intuitive

It is intuitive to anyone who understands floating point arithmetic. The same thing appears in a large number of common float operations - I don't see how this is directly related to the post.

Tony V E

unread,
Apr 25, 2018, 1:23:47 PM4/25/18
to Standard Proposals

Does fmod() currently have these same issues?

--
Be seeing you,
Tony

Hyman Rosen

unread,
Apr 25, 2018, 1:24:37 PM4/25/18
to std-pr...@isocpp.org
On Wed, Apr 25, 2018 at 1:17 PM, Jake Arkinstall <jake.ar...@gmail.com> wrote:
It is intuitive to anyone who understands floating point arithmetic.

No one understands floating-point arithmetic.  (Actually, that number of
people is not exactly zero, but you're supposed to compare those numbers
using ranges, right? :-)
 
The same thing appears in a large number of common float operations -
I don't see how this is directly related to the post.

The OP wrote  constexpr float f = 13.f % 2.1f; // f == 0.4
Seems pretty related to me.  They've asked for an operator,
given an example of its use, and described the result, a result
they would in fact not get if the operator were implemented. 

Tony V E

unread,
Apr 25, 2018, 1:26:31 PM4/25/18
to Standard Proposals
On Wed, Apr 25, 2018 at 12:57 PM, Jake Arkinstall <jake.ar...@gmail.com> wrote:
I'm also in favour of the change. We can talk about the uses of it and the pitfalls of floating representation until the cows come home, but that doesnt change that there are uses (justifying the existence of fmodf in the first place), that it is already deemed useful enough to be effortlessly implemented in a variety of other languages, and that the "different code for different types" ethos is not the C++ way.

Whether or not I believe that the change is feasible is another matter. I can only see three reasonable approaches. The first is to get the C community on board. Failing that, we could figure out a way of allowing operator functions on primitives without demolishing the language. Failing that, we could standardise a wrapping class around certain primitives that allows us to embellish them without the negotiations required for the previous two approaches.

These are in descending order of usefulness but ascending order of ease. 


Are any of those worth the time and effort?
If you had 10$ to spend on committee time/direction, how much would you allocate for this feature?
Doing this feature tends to mean NOT doing something else.

Hyman Rosen

unread,
Apr 25, 2018, 1:37:34 PM4/25/18
to std-pr...@isocpp.org
On Wed, Apr 25, 2018 at 1:17 PM, Jake Arkinstall <jake.ar...@gmail.com> wrote:
It is intuitive to anyone who understands floating point arithmetic.

And when someone does 0.5f % 0.1f and gets .099999994f, is that going to
be intuitive to them too?  Everyone is going to try to use this operator to do decimal
conversion (because what else do people want this operator for?) and they're going
to fail.

Jake Arkinstall

unread,
Apr 25, 2018, 2:22:46 PM4/25/18
to std-pr...@isocpp.org
The real stumbling block will be when they print it to the terminal and it rounds to 0.1. But this is trivial; 0.1 doesn't exist in a finite binary type. If they don't know that when they write the code then a necessary learning exercise presents itself to them. As soon as they realise that it's exactly the same problem as 3/3 = 0.99999... if you only have limited paper to work on, it is no longer a stumbling block. One would hope.

The same thing happens with fmod and fmodf. Was the discrepancy between decimal and binary representation of rationals considered a barrier when these functions were introduced too?

We are talking about an operator that performs an already understood function, allowing us to use a single piece of code on a more generic numerical type. This is the sole reason that I am contesting the idea that this is a reason not to have the operation - the existences of fmod and fmodf provide that justification.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Thiago Macieira

unread,
Apr 25, 2018, 4:51:27 PM4/25/18
to std-pr...@isocpp.org
On Wednesday, 25 April 2018 10:23:44 PDT Tony V E wrote:
> > As I said before, if floating-point % existed, then 13.0f % 2.6f would
> > result in
> > 0.40000057220458984375f exactly. The values written as 0.40000056f,
> > 0.40000057f, and 0.40000058f all convert to that value, but the value
> > written
> > as 0.4f does not, being exactly equal to 0.4000000059604644775390625f.
> >
> > This is not at all intuitive, even before you get to compiler permission
> > to keep
> > expression results in extended precision. Making an operator that fools
> > people
> > is going to make them unhappy.
>
> Does fmod() currently have these same issues?

It would help if we had a concrete example to test with. With infinite
precision, 13.0 % 2.6 should be zero, not 0.4.

In any case, a quick check with Godbolt shows the operation is not done in
infinite or even extended precision:

https://godbolt.org/g/AxCUnE

This shows the result of fmodf(13, 2.6) = 4.76837158E-7, not zero. Worse,
fmod(13, 2.6) is 2.5999999, which *is* 2.6. This is *extremely* surprising for
anyone who fails to stop and think about how floating point is actually
represented.

The other example in the thread (0.5 % 0.1) makes more sense. It should also
be zero, but the result offered by fmodf is within 1 ufp of 0.1. And like 13 %
2.6, the result with fmod is 0.1.

Because of those surprises, I'd advocate *not* to make a language operator.
Best leave it to a function which one needs to read the documentation for and
may thus find suitable warnings.

Hyman Rosen

unread,
Apr 25, 2018, 6:14:22 PM4/25/18
to std-pr...@isocpp.org
It would help if we had a concrete example to test with. With infinite
precision, 13.0 % 2.6 should be zero, not 0.4.

Sorry, I meant 2.1, not 2.6, as in the OP's example.

John McFarlane

unread,
Apr 25, 2018, 8:55:22 PM4/25/18
to std-pr...@isocpp.org
On Wed, Apr 25, 2018 at 9:31 AM Jakob Riedle <jakob....@gmail.com> wrote:
Am Dienstag, 24. April 2018 11:43:44 UTC+2 schrieb John McFarlane:
The remainder can be thought of as the value that is lost as a result of rounding down of the quotient. The rounding occurs because integers have a fixed resolution of 1. Floats do not.

For integer division, if n/d=q and n%d=r then if follows that q*d+r=n. So having a remainder of 0.4f in your example only makes sense if 13.f / 2.1f == 6 and that would change the behavior of floating-point division.

The modulo operation clearly has only one intuitive behaviour (excluded signed operands) which additionally has a significant amount of users that would benefit from such a change, regardles of whether the committee prioritises that way.

Then you would not like fixed-point modulo behavior which uses integer arithmetic but at scales which are powers of two.

Take the example of a fixed-point number with exponent +1. The resolution of such a number is 2. If 10 is represented with this type, then you can only take 3 away from it twice and you end up with a remainder of 4. This holds:

10/3 = 2r4  // numerator=10, denominator=3, quotient=2 and remainder=4

working back: 3*2+4=10  // d*q+r = n


So while modulo operation has only one intuitive behavior for integers (and floats observing integer arithmetic), it has a more general behavior which is unintuitive but nevertheless useful.


I am in favor of this change. +1

Jakob


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Hyman Rosen

unread,
Apr 26, 2018, 10:08:53 AM4/26/18
to std-pr...@isocpp.org
On Wed, Apr 25, 2018 at 8:55 PM John McFarlane <jo...@mcfarlane.name> wrote:
Then you would not like fixed-point modulo behavior which uses integer arithmetic but at scales which are powers of two.

Your funny numbers have an operator% defined, though, so maybe you're supporting the OP :-)

The basic problem is that a%b ≝ a-b×⌊a÷b⌋, and the division will not give people the
result they expect from examining the numbers they have written in the code, or otherwise
converted from decimal to binary, because those numbers are usually a tiny bit larger or a
tiny bit smaller than their decimal forms.  A lot of people don't understand this, and I would
guess that proportion is particularly high among those who are asking for a float
operator%.
If they knew what it would do, they wouldn't want it, because it doesn't do what they want.

John McFarlane

unread,
Apr 26, 2018, 11:31:33 AM4/26/18
to std-pr...@isocpp.org
On Thu, Apr 26, 2018, 07:08 Hyman Rosen <hyman...@gmail.com> wrote:
On Wed, Apr 25, 2018 at 8:55 PM John McFarlane <jo...@mcfarlane.name> wrote:
Then you would not like fixed-point modulo behavior which uses integer arithmetic but at scales which are powers of two.

Your funny numbers have an operator% defined, though, so maybe you're supporting the OP :-)

I'm not. The operator I'm describing fixed-point % -- just like integer % does.

The basic problem is that a%b ≝ a-b×⌊a÷b⌋, and the division will not give people the
result they expect from examining the numbers they have written in the code, or otherwise
converted from decimal to binary, because those numbers are usually a tiny bit larger or a
tiny bit smaller than their decimal forms.  A lot of people don't understand this, and I would
guess that proportion is particularly high among those who are asking for a float
operator%.
If they knew what it would do, they wouldn't want it, because it doesn't do what they want.

I agree but it sounds like you are still talking mostly about floating-point numbers. With binary fixed-point, I cannot do anything about the confusion caused by conversion from decimal fractions but at least the results are reasonably predictable, easy to calculate and completely precise. Given precise starting values, you can work back and get the exact dividend. Trying to figure out how floating-point modulo will turn out is a tougher task.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

3dw...@verizon.net

unread,
May 24, 2018, 3:24:19 PM5/24/18
to ISO C++ Standard - Future Proposals


On Tuesday, April 24, 2018 at 6:29:36 AM UTC-4, Tony V E wrote:
Would you be equally happy if fmod was made constexpr? 
(instead of % for floats)
 

I think that would be a great idea for most or all of the elementary transcendental functions.
My understanding is that writing to the global errno is what prevents this.
For fmod: If a domain error occurs, the global variable errno is set to EDOM.
This could happen for y == 0.

Maybe we can have overloads that return error_code?

That's a whole other conversation though.

3dw...@verizon.net

unread,
May 24, 2018, 3:57:28 PM5/24/18
to ISO C++ Standard - Future Proposals


On Tuesday, April 24, 2018 at 6:43:37 AM UTC-4, Jeff Hammond wrote:
Did you spend any time researching this topic before you posted?  The issue with your example isn't fmod but constexpr in <cmath> and the proposal to support this is linked from the top google search hit for "constexpr c++ cmath".

https://stackoverflow.com/questions/42189190/why-doesnt-the-c-standard-library-provide-constexpr-versions-of-the-cmath-fun points to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0533r0.pdf, which contains

constexpr float fmod(float x, float y); // see [library.c]
constexpr double fmod(double x, double y);
constexpr long double fmod(long double x, long double y); // see [library.c]
constexpr float fmodf(float x, float y);
constexpr long double fmodl(long double x, long double y);

 
Narrow types to the rescue:
template<typename Tp>
  remquo_t
  { Tp rem; int quo; };

remquo_t<Tp> remquo(Tp x, Tp y);

template<typename Tp>
  modf_t
  { Tp rem, quo; };

modf_t<Tp> modf(float value);

These are especially useful with decomp decls:

const auto [r, q] = remquo(x, y);

Reply all
Reply to author
Forward
0 new messages