Saturday, August 15, 2009

adventures in ignorance: modulo operator

Recently on the Perl Beginners mailing list I saw a new user having difficulty understanding the documentation for ||=. My first reaction was "hey, it is spelled out in straight forward English, ||= is like += but using || instead of +, go look up || and you there you are." Then I starting thinking about it. As a reference, perlop is less than optimal. Many of the operators are discussed tangentially (like ||=) and many others are never mentioned (like the file test operators, which I know are documented in perlfunc, but they look like operators to me). This has inspired me to write perlopref. I haven't socialized this anywhere but the Perl Beginners mailing list and here because I want to make sure the idea is viable first. So far it seems to be working for me, and I am learning a lot of the nooks and crannies I had been able to ignore in the past.

One of these nooks (or is it a cranny?) is the modulo operator (%), or more specifically what happens with negative numbers. I had never bother to consider how negative numbers would affect modulo. I found the text in perlop to be very opaque. Every time I tried to read it I found my eyes slipping down the page trying to get away, and I know what modulo does. I don't know if it is me, or the text, but I can't imagine trying to understand what the text was saying if I didn't already know what it did. Here is the part that covers modulo in my first draft of perlopref.pod (the pod is available here)

X % YDescription

This is the modulo operator. It computes the remainder of X divided by Y. The remainder is affect by the type of the numbers and whether they are positive or negative.

Given integer operands X and Y: If Y is positive, then X % Y is X minus the largest multiple of Y less than or equal to X. If Y is negative, then X % Y is X minus the smallest multiple of Y that is not less than X (i.e. the result will be less than or equal to zero). To illustrate this, here are the results of modding -9 through 9 with 4:

From this we can see a positive Y constrains X to a range from 0 to (Y - 1) that wraps around and a negative Y constrains X to a range from (Y + 1) to 0.

When Y is a floating point number whose absolute value is in the range of 0 to (UV_MAX + 1) (where UV_MAX is the maximum of the unsigned integer type) X and Y are truncated to integers. If the absolute value of Y is larger than (UV_MAX + 1) then the formula (X - I * Y) (where I is a certain integer that makes the result have the same sign as Y). For example, on 32-bit systems 4.5 % (2 ** 32 - 1) is 4, but 4.5 % 2 ** 32 is 4.5.

Note: when the integer pragma is in scope % gives you direct access to the modulo operator as implemented by your C compiler. This operator is not as well defined for negative operands, but it will execute faster.

3 comments:

This is very nice. What I like most is your remark about those stupid file test operators that I am never able to find in the documentation. Although I usually use perldoc from the commmand line, if I have to look up the file test operators, I have to rely on that bookmark.

Yeah, typing perldoc -f -X is not exactly intuitive. I am also thinking about modifying perldoc to take another switch to let you look up operators on their own like the -f switch does for functions: perldoc -O "X % Y". But I need to finish the POD before I start thinking too seriously about that. I current have 27 of the 74 operators in perlop's chart of operator precedence done. That number does not include filetest operators (27 more) and anything else I might find that should be in it (like the quote-like operators). If you want to look at what is done so far (or help by claiming a few operators), I have created a GitHub repository: perlopref.

It sounds good to me. I probably was programming perl for over 5 years before I stopped doing a man on 'perlop' before 'perlfunc' when looking for the file test operators. For part of that time, I just did a man on zshmisc, because most of the operators were roughly the same as zsh's, and I knew where those were.