Negative number modulo in swift
Solution 1:
The Swift remainder operator %
computes the remainder of
the integer division:
a % b = a - (a/b) * b
where /
is the truncating integer division. In your case
(-1) % 3 = (-1) - ((-1)/3) * 3 = (-1) - 0 * 3 = -1
So the remainder has always the same sign as the dividend (unless the remainder is zero).
This is the same definition as required e.g. in the C99 standard, see for example Does either ANSI C or ISO C specify what -5 % 10 should be?. See also Wikipedia: Modulo operation for an overview how this is handled in different programming languages.
A "true" modulus function could be defined in Swift like this:
func mod(_ a: Int, _ n: Int) -> Int {
precondition(n > 0, "modulus must be positive")
let r = a % n
return r >= 0 ? r : r + n
}
print(mod(-1, 3)) // 2
Solution 2:
From the Language Guide - Basic Operators:
Remainder Operator
The remainder operator (
a % b
) works out how many multiples ofb
will fit insidea
and returns the value that is left over (known as the remainder).The remainder operator (
%
) is also known as a modulo operator in other languages. However, its behavior in Swift for negative numbers means that it is, strictly speaking, a remainder rather than a modulo operation....
The same method is applied when calculating the remainder for a negative value of a:
-9 % 4 // equals -1
Inserting
-9
and4
into the equation yields:-9 = (4 x -2) + -1
giving a remainder value of
-1
.
In your case, no 3
will fit in 1
, and the remainder is 1
(same with -1
-> remainder is -1
).
Solution 3:
If what you are really after is capturing a number between 0 and b, try using this:
infix operator %%
extension Int {
static func %% (_ left: Int, _ right: Int) -> Int {
if left >= 0 { return left % right }
if left >= -right { return (left+right) }
return ((left % right)+right)%right
}
}
print(-1 %% 3) //prints 2
This will work for all value of a, unlike the the previous answer while will only work if a > -b.
I prefer the %% operator over just overloading %, as it will be very clear that you are not doing a true mod function.
The reason for the if statements, instead of just using the final return line, is for speed, as a mod function requires a division, and divisions are more costly that a conditional.