Understanding the modulo operator

The behavior of the modulo operator (%) can catch programmers by surprise as it is often misunderstood to provide the remainder of an arithmetic division operation. This article reviews the modulo operator behavior and provides an arithmetic division solution.

Modulo “Gotchas”

First of all modulo is an integer operator, and if it receives fractional arguments, Perl will only use the integer portion of the fraction. This means that the following two operations are equivalent:

my $result1 = 5.5 % 3.2;
my $result2 = 5 % 3;

Second the modulo operator is performing Euclidean division not arithmetic division. Mathematically this is expected, however that is why the characterization of modulo as returning the “remainder of a division operation” can catch programmers by surprise - it does not return a fractional decimal. For example:

my $result3 = 5 / 2; # 2.5
my $result4 = 5 % 2; # 1 (not 0.5)

Some languages (e.g. Haskell) implement a remainder function to provide the remainder from arithmetic division: where 5 over 2 would yield 0.5. Perl does not provide this out of the box, so a solution has to be coded or found on CPAN.

Implementing an arithmetic remainder function

The following subroutine returns the remainder from an arithmetic division operation. It takes two arguments: a dividend ($a) and a divisor ($b) and returns early for zero and undef arguments.

sub remainder {
    my ($a, $b) = @_;
    return 0 unless $b && $a;
    return $a / $b - int($a / $b);
}

print remainder(5, 2);  # 0.5
print remainder(1, 10); # 0.1
print remainder(9, 0);  # 0

Alternatively looking to CPAN, the Math::Decimal module provides a “dec_rem” subroutine (disclaimer - I have not tested it).

Further reading

perldoc has an entry for the modulo operator


This article was originally posted on PerlTricks.com.

Tags

David Farrell

David is a professional programmer who regularly tweets and blogs about code and the art of programming.

Browse their articles

Feedback

Something wrong with this article? Help us out by opening an issue or pull request on GitHub