Saturday, November 5, 2016

PowerShell Modulus operator is a remainder operator, not a modulus operator

The percent sign in PowerShell is known as the modulus operator. But it is in fact not a modulus operator. It is a remainder operator.

What’s the difference? Most of the time, nothing.

If both operands are positive, modulus and remainder are equivalent.

16 modulo 7 is 2, and the remainder of 16 divided by 7 is 2.

In some calculations used to find an index in a PowerShell array using negative operands, modulus and remainder are mathematically different, but functionally equivalent.

Sometimes in PowerShell, the “wrong” result works anyway.

For example, given the following function:

function Get-DayofWeek ( $StartDay = 0, $Offset = 0 )
{
$Weekdays = "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
$EndDay = ( $StartDay + $Offset ) % 7
return $Weekdays[$EndDay]
}

Get-DayofWeek -StartDay 0 -Offset  16
Get-DayofWeek -StartDay 0 -Offset -16

We are using % to calculate the index to the correct day of the week in the array. If the starting day (day zero) is on Sunday, day 16 will be on 16 modulo 7, or 2, which points to Tuesday.

If we count backwards 16 days from Sunday, -16 modulo 7 is 5, which points to Friday.

But % doesn’t do modulo, it finds the remainder, and the remainder of -16 divided by 7 is -2.

But it works anyway. In PowerShell, $WeekDays[5] points to the sixth element from the start of the array, and $WeekDays[-2] points to the second element from the end of the array. In an array with 7 elements, both of these point to the same element.

Modulus and remainder handle negative dividends differently

If we need to use the results from negative operands anywhere other than as the index of an array, we need to be aware of the difference between modulus and remainder, and understand that % performs a remainder operation.

For positive operands, modulus and remainder follow the same pattern.

%
DividendDivisorModulusRemainder
7311
6300
5322
4311
3300
2322
1311
0300

The difference is in what happens to that pattern when we carry on past zero.

For modulus, the pattern continues unchanged.

For remainder, the pattern reverses, and becomes negative.

%
DividendDivisorModulusRemainder
7311
6300
5322
4311
3300
2322
1311
0300
-132-1
-231-2
-3300
-432-1
-531-2
-6300
-732-1

Changing the sign of the divisor does not change the result of either modulus or remainder.

%
DividendDivisorModulusRemainder
7-311
6-300
5-322
4-311
3-300
2-322
1-311
0-300
-1-32-1
-2-31-2
-3-300
-4-32-1
-5-31-2
-6-300
-7-32-1