Upon writing
$a % 0
I am told that 0 is an illegal modulus.
However, according to "Concrete Mathematics: A Foundation for Computer Science", by Graham, Knuth (yes, that Knuth) and Patashnik 2nd ed. (page 82)
x mod y is defined as x  y{x/y} (where {} is floor) for y!=0, and x mod 0 is defined to be x.
This definition is justified; it preserves the property that x mod y always differs from x by a multiple of y, and makes sense if you think of it this way: x mod y means "map y to 0", so if y already is 0, then there is nothing to do, and x mod 0 should be congruent to x.
Yes, I know that division by 0 is a Bad Thing, but technically we are not dividing, we are defining the mod operator.
So this is more of a rant than a question, but it annoys me to lose functionality from one of my favourite operators in such an amusing language as Perl.
Re: 0 illegal modulus?
by Vynce (Friar) on Jun 11, 2001 at 07:11 UTC

well, you could override the modulus operator if you prefer, and use an idiom like
$ans = ($y*1) ? $x % $y : 0;
see overload for details.
.
 [reply] [d/l] 
Re: 0 illegal modulus?
by Zaxo (Archbishop) on Jun 16, 2001 at 12:31 UTC

Everybody, please pay attention to jepri. He's got it right.
The definition of Abel he mentions is that (perlishly):
my $num = $y*int($n) + $modulus;
This relation is uniquely satisfied by !$y && $modulus == $num
It does not involve division, allowing it to apply to algebrae lacking a multiplicative inverse (those are called modules).
It applies to floats too. Think $y = 2*$pi. Modulus is phase in that case.
Perl's % operator is really just remainder on integers, a bogosity which does not generalize well.
Don't fall into the trap of thinking your intuition or experience is a valid basis for modifying mathematical definitions. You will come to grief when a "proven correct" program crashes. You may blame math, but you will be wrong.
After Compline, Zaxo
Update: Rereading this, I realize that it sounds directed at nella. Not the case: this is a broadcast rant. nella started a fine thread, and seems to be on the side of the angels.
 [reply] [d/l] [select] 
Re: 0 illegal modulus?
by Cybercosis (Monk) on Jun 12, 2001 at 00:59 UTC

Well, had I designed the Perl interpreter (*chuckle*), I'd've made sure that mod 0 was illegal for consistancy with the assembly language on most (that I've dealt with) platforms. For instance, on the x86, the modulus is calculated by doing and I?DIV instruction, which leaves the remainder of the division (the modulus) in the appropriately sized register (AH, DX, or EDX). The brief upshot of this is that, since the modulus is actually calculated with a division, modulus 0 would give you a divide by 0 error. More of an explanation than a solution, really.  [reply] 
Re: 0 illegal modulus?
by nella (Novice) on Jun 12, 2001 at 01:04 UTC

I think that should be:
$ans = $y ? %x % $y : $x
Yes, this would work (but it still seems hackish). Thanks for the advice.
 [reply] [d/l] 

bash2.04$ perl e 'print 5 % foo'
Illegal modulus zero at e line 1.
so...
bash2.04$ perl e '$x = 5; $y = "foo"; print ($y ? $x % $y : $x); pri
+nt "\n"'
Illegal modulus zero at e line 1.
bash2.04$ perl e '$x = 5; $y = "foo"; print ($y*1 ? $x % $y : 0); pr
+int "\n"'
0
bash2.04$ perl e '$x = 5; $y = "foo"; print (($y*1) ? $x % $y : $x);
+ print "\n"'
5
as you can see, one still generates an error. as for what to return if $y is zero, i had misread your original statement.
.
 [reply] [d/l] [select] 

Dont use *1! Surely "foo" *is* an illegal modulus. And "0" is still false.
 [reply] 
Because it's not computing congruence
by mugwumpjism (Hermit) on Jun 15, 2001 at 14:20 UTC

In Mathematics terms, for two numbers A,B to be congruent mod N, then A  B must be an exact multiple of N. So in other words, it is a three argument comparison operator that returns a true/false value, rather than a two argument function like Perl's mod that returns a number between 0 and N1 (or N+1 and 0 if N is negative).
But Perl's (and other computer languages') mod operator is based on mapping numbers to what mathematicians call fields; in this case a "wraparound" set of numbers from 0 to N1 (or from N+1 to 0 if N is negative). In this context, a field with length 0 doesn't make much sense, so is by default an exception.
There are good reasons for this; for instance, much code assumes that if A = B mod N, then abs(A) < abs(N). (abs() being the absolute operator). Knuth's decision that "x mod 0 is defined to be x" may make sense to one school of thought, but to another it's bogus.
If you don't like the behaviour, use a ( $N ? $A % $N : $A ) construct, or see the section in Perl 6 on use limits, which allows you to define the behaviour of this special case.
Update: OK, IANAM and apparently it's only a field when N is prime. But hopefully you can understand what I mean :)
 [reply] [d/l] 

Bravo.
The bogosity in Knuth's argument, for any mathematicians who are interested, is that it is  from the point of view of at least one valid way of working with moduli  a patch for something that wasn't broken, and the Wrong Thing. From the point of view of the theory of limits, it's probably the Right Answer, but that doesn't (necessarily) mean that patching the modulus system to work that way is necessary or desirable.
I personally think that Perl's mod, and other computer languages', should behave the way Knuth's definition suggests, simply because I'd rather my functions gave answers than not. But I admit that it does, in various ways, break the consistency of the definition to do so.
Perl 6 is going to have special features for this kind of 'filled in' definition. Can someone enlarge for this relative newcomer on what use limits will do?
Tiefling (who is imaginary, but appears real at the limit)
BEGIN GEEK CODE BLOCK
Version: 3.1
GAT d++ s: a C++ UL P++ L++(+) E? W+(++) N+ o? K w+()
!O M V? PS+ PE Y PGP t+ 5 X+ R+++ tv b+++ DI++++ D+ G+ e++ h!() y
+?
END GEEK CODE BLOCK
 [reply] [d/l] [select] 
Re: 0 illegal modulus?
by ambrus (Abbot) on Sep 25, 2005 at 21:56 UTC

 [reply] 

#use DateTime::Util::Calc qw(mod);
#sub mod { $_[1]*1 ? $_[0] % $_[1] : 0);}
sub mod {
my($x)=$_[0];
my($y)=$_[1];
while($x >= 0){
$x=$y;
}
$x+=$y;
return($x);
}
 [reply] [d/l] 
A reply falls below the community's threshold of quality. You may see it by logging in. 

