-
Notifications
You must be signed in to change notification settings - Fork 1k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: New operator %% for positive-result Modulus operations #1408
Comments
I like the idea of a true modulo operator. I'm not sure |
The title of this proposal doesn't make any sense. The entire point of the modulo operation is to get the remainder that is produced from long-dividing two numbers, so there is no such thing as "true modulo" that isn't obtaining that remainder.
According to Wikipedia, there is no rigid mathematical specification of how modulo should work with negative numbers.
|
Let me be specific then: I want a Modulus operator which returns between 0 (incl) and divisor (excl). Also, Microsoft's own definition of the |
Then call |
And you want this operation for what exactly? What is this is the mathematical meaning of this operation? What code is |
@Joe4evr That does not do what I want, at all. The output value should loop around the bounds. As I've already stated the work-around is to add the second value if the result is negative. But this is not trivial (well, not as trivial as an operator), and there are compiler optimizations only possible with a true Modulus operation. |
Example use case: Let's say you divide a coordinate system into pieces of 100. If you are at position 5, you are at subposition 5 of piece 0. If you are at 230, you are at subposition 30 of piece 2. If you are at position -20, you are at subposition 80 of piece -1. The reason you're not at subposition -20 or 20 is because the subpositions should always be positive AND increasing when position is increasing. If we were at subposition -20 of piece 0 then piece 0 would be two times as large as any other piece. I am sure there are many, many more uses for Modulus, but this is what I have in mind. |
Are there really so many uses do justify adding a new operator? What's wrong with adding a |
Of course that's up for debate, but I would argue that a new operator is a good idea. I would also support adding a |
I changed the title to better reflect the issue, but technically it's wrong.
I couldn't fit all this into a short title, but hopefully it gets the point across. |
It probably makes more sense to do what Java does - add |
@aaronfranke I'm afraid the terminology you're using doesn't seem to be ideal. If people search the term ‘modulus,’ they'll discover that it's a synonym for ‘absolute value.’ Also, specifically, you're looking for the Euclidean variant of the modulo operation. (Or possibly the floored division variant? Can't tell.) C# already has the truncated division variant. |
It turns out Eric Lippert blogged about this exact thing back in 2011. |
@jnm2 I want what Eric Lippert calls "Canonical Modulus". I don't care if Modulus has conflicting definitions in the mathematical world (nobody in programming calls absolute value as "modulus"). I just want a math operator. |
Can you not just provide that operator in a library? Why does hte language need first class support for it? |
I already have a method for implementing it, but I think it should be in the language because it's very useful and I am not the only one who would like having this functionality. |
Anecdotally, I'm sure you believe this to be true. My own experience tells me the opposite. Without hard data from a significant percentage of the C# userbase, neither of us can be sure. |
There are already other doubled operators which are not boolean logic, such as |
@theunrepentantgeek Here is some data from some users: https://stackoverflow.com/questions/10065080/mod-explanation People are confused when they expect positive-result (really sign-of-divisor) answers and get negative answers in C#, and compare to languages like Python where positive-only (really sign-of-divisor) is the standard. Judging by "Viewed 68k times", and the amount of upvotes (remember that not every viewer of the question would upvote it), I would estimate that this is a fairly common problem. Providing an operator for canonical Modulus in C# would help these users out. |
Having the functionality be available would certainly be useful. That does not mean having the operator is necessary. For example, there are times i need to do an unsigned right shift. But do i need it to be an operator (like how java has it)? Nope. I just switch to unsigned math, do the right shift, then switch back. Unsigned shifts are still useful. But i can live without it being an operator. The same is true for this sort of mod/remainder for me. I can totally see the usefulness of it. I've even needed it at times. But that doesn't make me think i needed an operator for it. I would be totally fine with this coming in through the BCL, or just some numerics package. |
I would still like an operator, but, I agree with you @CyrusNajmabadi |
I remember in my early days of programming being really confused as to why my code wasn't working... and it's because everyone calls public static class ArrayExtensions
{
public static T WrapIndex<T>(this T[] source, int index)
=> source[index % source.Length];
} ...works just find for indexes greater than the size of the array but unfortunately doesn't work for negative indexes. To implement this function we need to detect whether the result came out negative and adjust it accordingly: public static class ArrayExtensions
{
public static T WrapIndex<T>(this T[] source, int index)
{
var wrapIndex = index % source.Length;
if (wrapIndex < 0)
wrapIndex += source.Length;
return source[wrapIndex];
}
} So in my opinion there's definitely a need for this functionality. Whether it needs its own operator or not is up for debate. I'd say yes, but that's because 99% of the time I want If anyone would like a visual representation of the difference between remainder and mod I've made a little diagram:
You can see that for positive numbers the two sequences are the same, but the differ for negative. As we pass through zero (approaching from the positive side) the |
Here is another example of when Modulus is more useful than Remainder. Let's say you're writing a program that finds out which day of the week it is. You can accomplish this by taking the amount of days and performing a Modulus by 7 on the days. Then it will always return between 0 and 6, 7 total values, for each day of the week. Unfortunately, this doesn't work with |
Examples can be found but the problem is that in reality dealing with negative numbers is less common so It's a bit baffling why everyone keeps taking about this modulus thing, I guess it's because many programmers have heard about modular arithmetic but less know about flooring and truncation. Also many seems to be miss the fact that the current reminder is defined in relation to division - So what's next? Propose adding |
I'm not asking floored-Division in this proposal (some languages like Python do have an operator for this: It's more common to need the modulus. You may want to know what day of the week or what sub-position etc but maybe not the sur-position. Operators are nice, but new methods in |
that is not a compelling use case to need an operator for me :) |
Yet another place which would profit from having this functionality available:
Here the mask is needed only in order to workaround the remainder behavior on negative numbers. I understand that the ship has already sailed, but from my experience remainder is almost exclusively used as modulus, so silent replacing of remainder with modulus would be not mentioned by the majority (modulo some workarounds for negative divisors, which would be just not necessary any more). |
And what problem would removing the |
Why would you need an operator for this? Why would a library method not be sufficient? |
As already stated in my previous post, there are no such instructions on any CPUs (well, at least on the ones that matter - x86/x64/arm32/arm64). x86/x64 CPUs have
Are you saying that
Well, I was simply replying to your claim that removing |
So if there are no negative times how come is this a use case? |
Calling it a modulus is perhaps incorrect; I just found I needed a wrap or rotation operator to operate |
I've been coding for 20+ years and I never needed the version of modulo operator which would return me the negative reminder. Grids, tables, array access, circular buffers, date wrappers - there are lots of use cases where you need a positive only reminder. I would be very surprised to see any practical use-case where negative reminder is needed. Thus, I would vote for %% operator or at least a corresponding method in Math. |
I landed here because I was among those that believed % was modulus, not remainder... started googling since it was "buggy". Oops. In fact I'm rather shocked that I got away with using it as modulus for so long, I'm suddenly concerned about where I may have left bugs. I have been programming in C# since its inception... it's embarrassing that I've not noticed what % really is until today when it went wrong. I am definitely behind %% because it's shorthand. Since we're talking use cases, mine: on setup I was auto selecting an item. The index to select may or may not be 'valid', and rarely it may be 'invalid' aka -1. In this case I just wanted it bound to a valid value, so I mistakenly used % operator on the index with list length as divisor. |
What I don't understand is why the way I'd love to hear of a real-life use case where this common My suspicion is that the annoying but more common sign handling for I'd throw my support behind this |
Porting between languages. I don't have to think about how the behavior will change when moving between existing code in many languages and C#, they just behave teh same way. |
@kshetline It all started with C, and most other languages copied this same behavior, including C++, C#, Java, JavaScript, GDScript, etc. It was a mistake made in the 1970s that will haunt us for centuries. A few languages have |
@CyrusNajmabadi, I already said "has been propagated ever since in the name of compatibility", so I recognized the portability argument. My question was clearly about what else besides compatibility does the C# implementation of Without a good example of that kind of utility, I'm inclined to go along with what @arronfranke just said, that it's "mistake made in the 1970s that will haunt us for centuries". |
Because there wasn't a compelling reason for us to go another path when designing the language. :) If we had a time machine, maybe someone could go back and make that argument 23 years ago. That said, even if someone had made that argument, it's likely compatibility would still have won out. Just not enough of a reason to go against the ecosystem as a whole here. |
@CyrusNajmabadi, I'm talking more broadly than C#. I'm asking how, before C# even existed, the ball got rolling in the first place so that the current I'm still curious if I'm wrong to call this behavior "broken". Is there is a non-compatibility-related use case where a negative result for a negative first operand and positive second operand is just perfect for some particular application, and I'd be oh-so-happy it works that way? At any rate, back to the specific proposal: If I'm correct to consider the proposed |
@aaronfranke, would you agree that, rather than producing an always-positive (or zero) result, that the proposed |
I imagine any domain where a remainder is wanted. |
"any domain where a remainder is wanted"... which is to say, "it's useful when what it does is what you want it to do" 😄 |
I mean... it makes sense to me. if we have integral division, you have two complimentary operations that makes sense together. i.e. If you want an actual modulus operator, it seems like having a simple method that does that would suffice. |
It would "suffice", but it still makes the modulus operation a second-class citizen. A "simple method" would also "suffice" for what
|
Only if we consider all APIs second class. It's not hte goal of the language to obviate the need for apis, or to absorb all of them into the language itself.
Yes. But see the above points about time machines and relitigating the past.
I honestly don't get what you want at this point. The language is what it is. it exists in an ecosystem of languages defined by behaviors created decades ago. There is little need or interest or benefit in changing any of that. |
Yes, the idea is for
This is what the code in the OP does. However, the most common use case is for
The argument for floor division is IMO a separate argument. Python has |
"I honestly don't get what you want at this point. The language is what it is." I want what @aaronfranke wants. This doesn't change what the C# language is any more than any other proposal, and this is hardly a radical or non-backward compatible proposal. Neither of us are asking that You seem baffled that anyone would want a new operator, as if the sole value of existing operators is their history of usage in other languages, and nothing else. If there was no Do you imagine that (1) ...instead of: (2) If you see (2) as an improvement over (1), and the proposed change introduces no backwards compatibility problems whatsoever, why do you treat the idea of an operator for modulus as totally baffling? It's the same kind of improvement, just for a less-commonly used operation. (And for that matter, C# could definitely use the |
Why do you think that?
This is a strawman. I didn't say operators were frivolous. I said that i don't see the value in there being a dedicated operator for this.
I never said i was baffling. Maybe you're thinking of someone else?
Feel free to file a proposal on it. I don't really see hte value being there myself, but maybe someone on the ldm will. -- Look, i'm sorry that you're not finding much sympathy from me on this particular issue. I know that every issue that people file on csharplang is important to some group of people. However, it's not going to be the cae that every issue is important ot everyone, or that every issue will find a supporter on the LDM. In this case, i've simply shared with you my thoughts here and why I would not champion this myself. I would have no problem with some other LDM member doing so, but i at least wanted to let you know the thinking that goes into it. |
I wholeheartedly agree with the OP. Edit: |
Actually, % used to mean "divide by 100". Many programming languages use it, however, for the remainder operation and very few for modulus. |
@quinmars % is not ÷ EDIT: Sorry, completely missed the "by 100" part. |
@aaronfranke, correct. % is the "per cent" sign. |
I think @aaronfranke and @kshetline have both articulated the issues with the existing implementation of
|
Moving to a discussion which is the current path for new ideas. |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Note: The title is slightly incorrect because it's hard to describe the behavior completely in a short title. The idea is for
a %% b
to be on the range[0, b)
, soa %% -3
would be on the range[0, -3)
. As usual, the pattern holds that asa
increases, so does the output. However, by far the most common case is forb
to be positive, and in that case the title is correct.Currently, C# has the operator
%
for the Remainder operation. This is different from the canonical Modulus when it comes to negative numbers. For example,-5 % 8
is-5
with the Remainder operation but it is3
with the Modulus operation (proposed syntax:-5 %% 8
returns3
).Modulus always returns between 0 (inclusive) and the second argument (exclusive). Yes, this means that it should keep the sign of the second argument.
a %% 8
is on range [0, 8)By contrast, Remainder can return between the negative second argument (exclusive) and the second argument (again, exclusive).
a % 8
is on range (-8, 8)Currently, I implement Modulus on top of Remainder in my program like this:
A new operator,
%%
, would serve the following purposes:Easily allow the writing of true canonical Modulus operations, rather than Remainder operations. I can imagine more use cases for this.
As @quinmars noted, the compiler itself performs optimizations to change
%
to bitwise when it is passeduint
types. Therefore, the compiler could also improve the performance of the%%
true Modulus operation, when givenint
types rather thanuint
(int
is much more common thanuint
), and the second argument is a power-of-two, by making it bitwise.Make developers aware of the issue and endorse the correct usage. To quote @vladd:
A few use cases from the replies below:
Indexes in arrays, tables, bucket hash tables, circular buffers, and ring buffers.
Finding sub-positions in a grid coordinate system.
Working with angles.
Working with dates and times.
The text was updated successfully, but these errors were encountered: