Modulo operation in Swift?

Hi all!
Is there a modulo operation/function in Swift? I want the "true"
mathematical modulo (as % in Python), and not remainder (as % in Swift).

Do I have to implement this basic mathematical function myself and if so
what is the best way to write it (it will be heavily used so I want it to
be as fast as possible)?

/Jens

1 Like

There was a discussion in swift-evolution, starting at

  [swift-evolution] [Pitch] 'Double modulo' operator

about adding a "true modulo" operator to the standard library. There were different opinions whether

- such a thing needs to be in the standard library at all, and if yes:
- if it should be an operator or function,
- how it should be named.

As far as I know, nothing happened until now. The above posting contains a possible (Swift 3) implementation. In Swift 4 that would be

    infix operator %%: MultiplicationPrecedence

    func %%<T: BinaryInteger>(lhs: T, rhs: T) -> T {
        return (lhs % rhs + rhs) % rhs
    }

I would probably do (as an operator or as a function)

    func %%<T: BinaryInteger>(lhs: T, rhs: T) -> T {
        let rem = lhs % rhs // -rhs <= rem <= rhs
        return rem >= 0 ? rem : rem + rhs
    }

with one division instead of two.

Regards, Martin

···

Am 09.11.2017 um 12:43 schrieb Jens Persson via swift-users <swift-users@swift.org>:

Hi all!
Is there a modulo operation/function in Swift? I want the "true" mathematical modulo (as % in Python), and not remainder (as % in Swift).

Do I have to implement this basic mathematical function myself and if so what is the best way to write it (it will be heavily used so I want it to be as fast as possible)?

/Jens
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

4 Likes

Why is % not available for floating point numbers?

···

On Nov 9, 2017, at 04:51 , Martin R via swift-users <swift-users@swift.org> wrote:

There was a discussion in swift-evolution, starting at

[swift-evolution] [Pitch] 'Double modulo' operator

about adding a "true modulo" operator to the standard library. There were different opinions whether

- such a thing needs to be in the standard library at all, and if yes:
- if it should be an operator or function,
- how it should be named.

As far as I know, nothing happened until now. The above posting contains a possible (Swift 3) implementation. In Swift 4 that would be

   infix operator %%: MultiplicationPrecedence

   func %%<T: BinaryInteger>(lhs: T, rhs: T) -> T {
       return (lhs % rhs + rhs) % rhs
   }

I would probably do (as an operator or as a function)

   func %%<T: BinaryInteger>(lhs: T, rhs: T) -> T {
       let rem = lhs % rhs // -rhs <= rem <= rhs
       return rem >= 0 ? rem : rem + rhs
   }

with one division instead of two.

Regards, Martin

Am 09.11.2017 um 12:43 schrieb Jens Persson via swift-users <swift-users@swift.org>:

Hi all!
Is there a modulo operation/function in Swift? I want the "true" mathematical modulo (as % in Python), and not remainder (as % in Swift).

Do I have to implement this basic mathematical function myself and if so what is the best way to write it (it will be heavily used so I want it to be as fast as possible)?

/Jens
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Rick Mann
rmann@latencyzero.com

This has been discussed extensively. Swift had this this operator originally, but we removed it. Here’s the rationale I gave back then:

···

On Nov 9, 2017, at 10:55 AM, Rick Mann via swift-users <swift-users@swift.org> wrote:

Why is % not available for floating point numbers?

-----------

While C and C++ do not provide the “%” operator for floating-point types, many newer languages do (Java, C#, and Python, to name just a few). Superficially this seems reasonable, but there are severe gotchas when % is applied to floating-point data, and the results are often extremely surprising to unwary users. C and C++ omitted this operator for good reason. Even if you think you want this operator, it is probably doing the wrong thing in subtle ways that will cause trouble for you in the future.

The % operator on integer types satisfies the division algorithm axiom: If b is non-zero and q = a/b, r = a%b, then a = q*b + r. This property does not hold for floating-point types, because a/b does not produce an integral value. If it did produce an integral value, it would need to be a bignum type of some sort (the integral part of DBL_MAX / DBL_MIN, for example, has over 2000 bits or 600 decimal digits).

Even if a bignum type were returned, or if we ignore the loss of the division algorithm axiom, % would still be deeply flawed. Whereas people are generally used to modest rounding errors in floating-point arithmetic, because % is not continuous small errors are frequently enormously magnified with catastrophic results:

  (swift) 10.0 % 0.1
    // r0 : Double = 0.0999999999999995 // What?!

[Explanation: 0.1 cannot be exactly represented in binary floating point; the actual value of “0.1” is 0.1000000000000000055511151231257827021181583404541015625. Other than that rounding, the entire computation is exact.]

Proposed Approach:
Remove the “%” operator for floating-point types.

Alternative Considered:
Instead of binding “%” to fmod( ), it could be bound to remainder( ), which implements the IEEE 754 remainder operation; this is just like fmod( ), except instead of returning the remainder under truncating division, it returns the remainder of round-to-nearest division, meaning that if a and b are positive, remainder(a,b) is in the range [-b/2, b/2] rather than [0, b). This still has a large discontinuity, but the discontinuity is moved away from zero, which makes it much less troublesome (that’s why IEEE 754 standardized this operation):

  (swift) remainder(1, 0.1)
    // r1 : Double = -0.000000000000000055511151231257827 // Looks like normal floating-point rounding

The downside to this alternative is that now % behaves totally differently for integer and floating-point data, and of course the division algorithm still doesn’t hold.

Ah, I see.

So, here's my issue. I recently ported some C code for satellite position prediction to Swift. This code used fmod() a lot. I had thought fmod() was just % for floats, but I see now it's not.

What is truncatingRemainder in all this? It would be great if there were a documentation section covering this in detail (in the context of Swift). It's confusing because fmod() is available, but so are the other options.

Should %% be something the language provides for IEEE 754 remainder()?

···

On Nov 9, 2017, at 11:18 , Stephen Canon <scanon@apple.com> wrote:

On Nov 9, 2017, at 10:55 AM, Rick Mann via swift-users <swift-users@swift.org> wrote:

Why is % not available for floating point numbers?

This has been discussed extensively. Swift had this this operator originally, but we removed it. Here’s the rationale I gave back then:

-----------

While C and C++ do not provide the “%” operator for floating-point types, many newer languages do (Java, C#, and Python, to name just a few). Superficially this seems reasonable, but there are severe gotchas when % is applied to floating-point data, and the results are often extremely surprising to unwary users. C and C++ omitted this operator for good reason. Even if you think you want this operator, it is probably doing the wrong thing in subtle ways that will cause trouble for you in the future.

The % operator on integer types satisfies the division algorithm axiom: If b is non-zero and q = a/b, r = a%b, then a = q*b + r. This property does not hold for floating-point types, because a/b does not produce an integral value. If it did produce an integral value, it would need to be a bignum type of some sort (the integral part of DBL_MAX / DBL_MIN, for example, has over 2000 bits or 600 decimal digits).

Even if a bignum type were returned, or if we ignore the loss of the division algorithm axiom, % would still be deeply flawed. Whereas people are generally used to modest rounding errors in floating-point arithmetic, because % is not continuous small errors are frequently enormously magnified with catastrophic results:

  (swift) 10.0 % 0.1
    // r0 : Double = 0.0999999999999995 // What?!

[Explanation: 0.1 cannot be exactly represented in binary floating point; the actual value of “0.1” is 0.1000000000000000055511151231257827021181583404541015625. Other than that rounding, the entire computation is exact.]

Proposed Approach:
Remove the “%” operator for floating-point types.

Alternative Considered:
Instead of binding “%” to fmod( ), it could be bound to remainder( ), which implements the IEEE 754 remainder operation; this is just like fmod( ), except instead of returning the remainder under truncating division, it returns the remainder of round-to-nearest division, meaning that if a and b are positive, remainder(a,b) is in the range [-b/2, b/2] rather than [0, b). This still has a large discontinuity, but the discontinuity is moved away from zero, which makes it much less troublesome (that’s why IEEE 754 standardized this operation):

  (swift) remainder(1, 0.1)
    // r1 : Double = -0.000000000000000055511151231257827 // Looks like normal floating-point rounding

The downside to this alternative is that now % behaves totally differently for integer and floating-point data, and of course the division algorithm still doesn’t hold.

--
Rick Mann
rmann@latencyzero.com

Use fmod(x,y). It is identical to C fmod(x,y). It’s also identical to x.truncatingRemainder(dividingBy: y).

···

On Nov 9, 2017, at 1:12 PM, Roderick Mann <rmann@latencyzero.com> wrote:

Ah, I see.

So, here's my issue. I recently ported some C code for satellite position prediction to Swift. This code used fmod() a lot. I had thought fmod() was just % for floats, but I see now it's not.

What is truncatingRemainder in all this? It would be great if there were a documentation section covering this in detail (in the context of Swift). It's confusing because fmod() is available, but so are the other options.

Should %% be something the language provides for IEEE 754 remainder()?

On Nov 9, 2017, at 11:18 , Stephen Canon <scanon@apple.com> wrote:

On Nov 9, 2017, at 10:55 AM, Rick Mann via swift-users <swift-users@swift.org> wrote:

Why is % not available for floating point numbers?

This has been discussed extensively. Swift had this this operator originally, but we removed it. Here’s the rationale I gave back then:

-----------

While C and C++ do not provide the “%” operator for floating-point types, many newer languages do (Java, C#, and Python, to name just a few). Superficially this seems reasonable, but there are severe gotchas when % is applied to floating-point data, and the results are often extremely surprising to unwary users. C and C++ omitted this operator for good reason. Even if you think you want this operator, it is probably doing the wrong thing in subtle ways that will cause trouble for you in the future.

The % operator on integer types satisfies the division algorithm axiom: If b is non-zero and q = a/b, r = a%b, then a = q*b + r. This property does not hold for floating-point types, because a/b does not produce an integral value. If it did produce an integral value, it would need to be a bignum type of some sort (the integral part of DBL_MAX / DBL_MIN, for example, has over 2000 bits or 600 decimal digits).

Even if a bignum type were returned, or if we ignore the loss of the division algorithm axiom, % would still be deeply flawed. Whereas people are generally used to modest rounding errors in floating-point arithmetic, because % is not continuous small errors are frequently enormously magnified with catastrophic results:

  (swift) 10.0 % 0.1
   // r0 : Double = 0.0999999999999995 // What?!

[Explanation: 0.1 cannot be exactly represented in binary floating point; the actual value of “0.1” is 0.1000000000000000055511151231257827021181583404541015625. Other than that rounding, the entire computation is exact.]

Proposed Approach:
Remove the “%” operator for floating-point types.

Alternative Considered:
Instead of binding “%” to fmod( ), it could be bound to remainder( ), which implements the IEEE 754 remainder operation; this is just like fmod( ), except instead of returning the remainder under truncating division, it returns the remainder of round-to-nearest division, meaning that if a and b are positive, remainder(a,b) is in the range [-b/2, b/2] rather than [0, b). This still has a large discontinuity, but the discontinuity is moved away from zero, which makes it much less troublesome (that’s why IEEE 754 standardized this operation):

  (swift) remainder(1, 0.1)
   // r1 : Double = -0.000000000000000055511151231257827 // Looks like normal floating-point rounding

The downside to this alternative is that now % behaves totally differently for integer and floating-point data, and of course the division algorithm still doesn’t hold.

--
Rick Mann
rmann@latencyzero.com

1 Like