fslang-suggestions icon indicating copy to clipboard operation
fslang-suggestions copied to clipboard

Addition of a correct modulus operator

Open Happypig375 opened this issue 4 years ago • 9 comments
trafficstars

Addition of a correct modulus operator

The current remainder operator % can be surprising in that the sign of the result follows the sign of the dividend, so does not output periodic results for a fixed divisor. Changing the current behavior of % has been declined in https://github.com/fsharp/fslang-suggestions/issues/417, so another way forward would be to add a new operator, which, like a true modulus operator, would output positive results regardless of its inputs. By always outputting positive results, we would achieve predictability and ease of use for periodic computations.

From F#'s OCaml roots, mod is keyword for an infix operator already, and is currently undefined in FSharp.Core:

let inline (mod) D d =
    let r = D % d
    if r >= LanguagePrimitives.GenericZero then r
    elif d >= LanguagePrimitives.GenericZero then r + d
    else r - d
// Usage: -5 mod 3

The existing way of approaching this problem in F# is to include such a definition everytime we use the operator, or bite ourselves when trying to use % on negative dividends.

Pros and Cons

The advantages of making this adjustment to F# are

  1. Raise awareness of the true modulus operator
  2. Less duplicated code across projects
  3. Assigning novel uses to existing available operators

The disadvantages of making this adjustment to F# are that the presence of both % and mod can be confusing. However, upon realisation that % stands for the remainder operation instead of modulus, and recognising the difference between the two operations, this can be solved.

Extra information

Estimated cost (XS, S, M, L, XL, XXL): XS

Related suggestions:

  • https://github.com/fsharp/fslang-suggestions/issues/417

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • [x] This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • [x] I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • [x] This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • [x] This is not a breaking change to the F# language design
  • [x] I or my company would be willing to help implement and/or test this

For Readers

If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.

Happypig375 avatar Aug 30 '21 10:08 Happypig375

[...] a new operator, which, like a true modulus operator, would output positive results regardless of its inputs.

I think you should be more precise here. "The true modulus operator" returns a quotient group, not an integer (and certainly not a finite percussion int). In a congruence like

3 mod 2 \equiv 1

the symbol 1 does not represent the integer 1 but the set of all odd numbers. It would also be correct to replace it with 3, because it is also an odd number. Using the symbol 1 there instead of something else like 3 is merely convention because it is the canonical representation of the set of odd numbers.

TysonMN avatar Sep 05 '21 12:09 TysonMN

Two uses for integer division (n div m, n mod m):

  • Division with remainder. Here the conventional definition in mathematics, for m > 0, is n = mq + r, where 0 ≤ r <m.
  • Finding quotient equivalence classes.

The definitions are intentionally compatible: the remainder found in the conventional definition, when applied to different n differing by a multiple of m, gives the same output.

In each case dotnet % is incorrect, for n < 0 and m > 0. E.g. -3 mod 2 should give 1 but gives -1. This contradicts the conventional definition in mathematics, since -1 < 0, and it also doesn't find a quotient equivalence class, since -3 mod 2 = 3 mod 2 evaluates to false instead of true.

charlesroddie avatar Jul 04 '22 08:07 charlesroddie