After the discussion a few weeks back about zero and the quirks it introduces in mathematics, I realized there were some other mathematical points that could be brought up with respect to Perl and programming... and (hopefully) we won't need Math degrees to understand these. :-)
Exponentiation (0^0)
I forget exactly what I was doing to get to the point where I was doing something in Perl that used "0 ** 0" (it was probably another obfu...), but after I realized that the results didn't agree with what I thought they should be, I tried the expression (modified for the various platforms, of course) in a few different places:
My point is that I'm getting a consistent result of 1 with the computer languages I can try out... but from what I know of Mathematics, that just ain't right. And to make things more troubling for my psyche, I'm getting answers that support me from my calculators... and I've got two Microsoft products telling me different things. But that's no surprise.
For those who are wondering what the answer should be... well, until I played around with all this, I was pretty sure the answer was undefined. And I'm still pretty sure of that, but now I'm trying to figure out just how these operations are defined in the various languages to get these results.
So my question here is: What's going on?!? Is this another case of programming math gone wrong? And if all these languages are willing to choke on division by zero, why won't they choke on this? Speaking of that subject...
Division by zero
In addition, I have another point which fits in with this discussion of mathematical murkiness. In virtually (?) all programming languages, "x / 0" will result in some sort of Very Bad Thing happening. In C, the program will die. In Java, an ArithmeticException is thrown. In Perl, the script will also die unless you do something eval. (I'm sorry, that's a horrible pun -- please don't throw moldy cheese at me.)
My point here is that, given Perl's undef value, it sounds a lot nicer to say something like:
funkshun( EXPR ) if defined ( EXPR );
... than it is to do this:
eval EXPR;
funkshun( EXPR ) unless ($@);
So why can't dividing by zero result in an undefined value, as mathematics would have us believe? Division by zero would still result in a few warnings under -w if this undefined value was used later on, correct? I guess what I'm really saying is that I don't think that this should be the (near-)fatal problem that it is at the moment, as it really doesn't fit with (what I perceive as) Perl's "enough rope to hang yourself" idea...
... of course, that's just my opinion. It's likely quite incorrect. ;-) Your thoughts?
His Royal Cheeziness
Re: More Fun with Zero!
by ariels (Curate) on Jul 23, 2001 at 12:58 UTC
|
00
Defining 00=1 is a good idea, because it makes the easy things easy and the hard things possible. For instance, the binomial theorem says
(a+b)n = ∑k=0n Ck,n akbn-k,
where Ck,n=n!/(k!(n-k)!) is the binomial coefficient.
Only to you, it doesn't. Because when n=0, a=0 and b!=0, the left hand side is defined but the right hand side isn't. Of course, if you agreed that 00=1 then the right hand side would be defined and you'd have equality.
Or take the exponential function:
exp(x) = ∑n=0∞ xn/n!
(and similar expansions for sin and cos, not to mention any other Taylor expansion). This requires you to believe that 0!=00=1, or you'll have trouble reading the first term (which always uses 0!), and if x=0 you'll also have a 00 there.
Or believing that am+n = aman (when a=0, m=-n). It all requires you to believe that 00=1, or spend the rest of your life writing down pointless special cases.
Why is /0 an error?
So if 00=1 for convenience, why do I refuse to accept a more "convenient" behaviour of division by zero -- return undef instead of an error?
Because the error is more convenient! First, note that there's no "convenient" value to return for x/0, ever. Which is why CheeseLord wants to get back the non-numeric undef.
Which might be nice for $a=$b/$c. Except that then you have to test for defined($a) afterwards, where previously you'd test for $c==0 beforehand.
Next, there's the problem of implicit conversion of undef to 0 in numeric expressions. We certainly don't want 5+17/0 == 5 (and if you still think we do, do you also want 1/0 < 1/10?)
So we'd have to do something more clever about undef in numerical operations, say having all results undef in the presence of an undef operand. Apart from probably being slower (a well-worn excuse, and not particularly convincing by now), you still have to test your return value to see if it's undef. And you get significantly less information about the precise source of the undef (although with Perl6 attributes, perhaps you could get more information in such a case).
How does
And, of course, such "propogated undef" semantics break every existing line of Perl...
So here's a challenge for anyone (CheeseLord or otherwise) who'd like to have ! defined(x/0) in Perl, along with "propogated undef": show some code that is clearer to express with these semantics than in the present case.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Alert: Those who hate discussions about mathematics should skip immediately to the second section of this node. Thank you. :-)
00 == ??
Because when n=0, a=0 and b!=0, the left hand side is defined but the right hand side isn't.
Correct. But if a=0, what's the point of using the binomial theorem (since (a+b)n = bn). Likewise, if either a or b equal 0, the binomial theorem is a waste of energy. It makes sense to use a special case there, IMO.
As far as your remarks go on the Taylor expansions, I can't say my Calculus is as strong as it should be, and considering that you've said you're a mathematican, I'll accept that you know much more about this and very likely are correct.
But I do have to disagree with your comment about pointless special cases... Special cases have that name because that's what they are -- occurrances that deserve special attention to be paid to them. In many cases, though, it has been dealt with by deciding that 0! = 1, or that x0 = 1, which I'm fine with. As far as 00 goes, I don't really know what it should be. That's why I posted this. :-) But without special cases, I can easily make the entire imaginary number system useless in about twenty seconds by proving that i = 1. Because sqrt(ab) == sqrt(a) * sqrt(b) only when both numbers are rational real, though, my plot to destroy mathematics has been foiled -- for now, anyway. ;-)
"if defined ($x / 0) ..."
...there's the problem of implicit conversion of undef to 0 in numeric expressions.
This problem doesn't exist now because the program will die if the exception isn't trapped. But note that this error will be noted if the script is coded with -w on. In addition, this error will likely never occur if the programmer thinks ahead and does the c == 0 test you describe. My point is that Perl's watching out for a me a little more than I'd like it to.
I can give you an analogy... if you've ever used Java, you likely know the difference between an Exception and a RuntimeException -- not catching the possibility of the former is a compile-time error, while checks for the latter can be omitted (after all, nobody wants to check for ArrayIndexOutOfBoundsException every time they access an array), but will still cause program termination if thrown. As I see it, dying on division by zero is like Java's forcing of checking for IOException whenever dealing with files. I like the fact that Perl gives me the option on an open call to check the return value. Sure, it may not promote great code, and I certainly won't do it when writing anything worthwhile, but I want to be free when writing my quick 3-minute script to rename a bunch of files to not put or die "$!" after I open a file, dammit!! :-)
And that's my complaint with the error for dividing by zero -- Perl is pretty nice about not dying on most things, and right now, I don't understand why it's necessary to make it a fatal error. As it stands, changing the result of a division by zero to undef will not break any code that isn't already inherently broken (AFAIK). And it might allow me to get away with output like this (although, only without -w):
Your average is:
Which, to me, anyway, is nicer than saying that my average is zero when I don't have any entries. :-) Once again, though, it's just my opinion.
Update: Corrected idiotic mistake in terminology ("rational" v. "real").
His Royal Cheeziness | [reply] [Watch: Dir/Any] [d/l] |
Re (tilly) 1: More Fun with Zero!
by tilly (Archbishop) on Jul 23, 2001 at 16:56 UTC
|
I have to agree with what everyone said, but I am
going to try to give explanations that don't involve
Calculus since most people don't know Calculus.
There is a field of mathematics called "Combinatorics".
You may not know what that is, but it isn't as scary as
Calculus because it is not nearly as complicated. This
field is about studying the ways of combining a finite
number of things, and typically what you study is the
number of ways of counting things. So from the point
of view of combinatorics, what are the operations +, *,
**, and factorial?
Well m + n is the operation of taking two
groups of m and n things,
putting them together, and then counting the combined
group. So 0+0 is putting nothing with
nothing and counting nothing, so you get 0
again.
As we all know, m * n is the operation of
taking m things along one axis, n
things along another axis, creating a rectangle, and then
counting up unit squares in the rectangle. So
0*0 is making a rectangle with no height and
no width then realizing that its area is 0, so you get
0 back.
Analogies with these two familiar operations are probably
why many people have incorrect expectations of what happens
with powers and factorial.
When we write mn what
we are counting are the number of ways there are to pick
out n things from a set of m in
order with repetition allowed. Since each choice you
make gives you m times as many things, we
are used to calculating it with m*m*...*m
where the number of m's is n.
But that calculation leaves many of us confused over
what 00 is supposed to be. Well forget the
formula, go back to basics. If I want to pick nothing
from no things, I can do nothing! There is
no other thing I can do, but I do have one way to
accomplish the task. And that is to look back, grin,
and say I have no work to do, the task is accomplished!
So 00 is 1 since there is one way to pick
nothing from no things.
Similarly with factorial. n! is the number
of ways to arrange n things in order. Again we have a
well-known formula for it. But again the well-known
formula does not give most people any insight as to what
0! should be. But right now take a look at
a collection of no things. Well they are in an
arrangement already, can we rearrange them? Not that I
can see! So there is exactly one way to arrange 0
things in order, and that is to leave that space empty!
Therefore 0! is 1.
Still not convinced? Well there is a more fundamental
mathematical principle at work here. In many places in
mathematics you have formulas where you have to add
two sets of things together. So you can add them up
separately and then add together the sums. In others
you want to multiply two sets of things together. So
you multiply them separately and then multiply together
the products. ariels offers examples of both
involving the binomial theorem and Taylor series. But
the concept is clear.
But the special case that arises is what you do when
one of the sets has no things in it? How do you add
together no things? How do you multiply no things?
What answer makes sense?
Well the overriding principle is that how you divide a
set up first should make no difference to the final sum
or product. So if I take a set of numbers and break it
into that set and an empty set, add them separately,
then add them together, I have to come to the actual
sum. Which is only going to work if adding the sum of
no things doesn't change anything. Ditto for
multiplication. Multiplying a set of numbers together
should be the same as breaking it into the entire set
and an empty set, multiplying them separately, then
multiplying them together.
As we all know, the only thing you can add and not
change anything is 0, for which reason 0 is called the
additive identity. Therefore the empty sum is always
0 in mathematics. Likewise 1 serves the same role in
multiplication that 0 serves in addition. Multiplying
by 1 changes nothing. So the only reasonable answer
to get from multiplying nothing is 1. And since powers
and factorial both work out to be formulas that
involve a series of multiplications, not additions, the
answer in the degenerate case (ie 0! and
n0) is an empty
product which is 1.
As for division by 0, there is a simple reason for
making that a trappable error. The vast majority of
the time when a programmer winds up dividing by 0,
that wasn't what was intended and is a sign of a
fairly serious bug. So you don't want to make it
undef and sweep it under the rug. However there are
times when the programmer needs to check the error so
you make it trappable.
You might not believe me, but if you do a lot of
programming with numbers, just pay attention. Most of
the time when you get that error, was it a sign of
something that was really wrong? (It is for me.)
UPDATE
jynx pointed out an obvious typo. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Yea, Combinatorics should be much more interesting to the layman than Calculus. It was invented so that he could be a better poker player!
| [reply] [Watch: Dir/Any] |
|
Hmm, how many ways are there to pick no things from n things, when n is not zero, but say 42?
I can not pick the first item. I can not pick the second item. By your reasoning, the answer to n**0 should be the power set of n.
If "doing nothing" is allowed as an operation, then that messes up the normal cases, too. Say you want to choose 3 items. You pick three, but then can optionally not pick any of the others.
| [reply] [Watch: Dir/Any] |
|
You are confusing yourself with verbal games.
The ways of choosing spoken of have to do with what
choices are made, in what order. They do not speak of
whether the choice is made by entering an electronic
record, shouting to a crowd, or with a quill pen. It is
irrelevant how many bathroom breaks you take in your
arduous task. It is all a question of what choices you
made in what order.
There is one way to make no choices from 42 things. It
matters not whether you describe this as failing to turn
your paper in, or turning in a blank paper.
There are 42 ways to make one choice from 42 things. It
matters not how many times you think of making no choices,
they don't get recorded.
There are 1764 ways to make 2 choices with repetition
allowed from 42 things. If you think of the operation
as making a choice, making no choices 500 times, and then
making your second choice, it matters not. The number of
pauses is not relevant, and each time you don't
choose you have only 1 way to do that. With this strange
model you have complicated the overall calculation by
multiplying by 1 500 times, which changes nothing.
I could go on, but I think the point is clear. From
number theory to combinatorics to analytics it is widely
accepted that an empty sum is 0 and an empty product is 1.
This does not mess up the usual model of anything. In
fact it is the usual model used by mathematicians...
| [reply] [Watch: Dir/Any] |
|
Given a set containing N elements, how many different subsets are there that contain P elements? For P==0, the answer is always 1, the empty set.
Does that make it easier for you to understand? Update: Um, that sounds harsher than I intended it. For what it's worth, I found tilly's explanation hard to understand. I knew what he was getting at but the way he described there being only one possible choice of actions (no action) wasn't convincing to me, even leading me to thinking "there is no way to pick 0 things from 0 things because there is nothing to pick from". But changing terminology makes it very easy to understand, I think. The only choice I can make is to give you the empty set, the set that contains no items. So I'm not giving you zero sets, I am giving you one set.
-
tye
(but my friends call me "Tye")
| [reply] [Watch: Dir/Any] |
Re: More Fun with Zero!
by lemming (Priest) on Jul 23, 2001 at 13:07 UTC
|
According to this math link, there's
still some discussion over what the result should be.
Update: it starts with
According to some Calculus textbooks, 0^0 is an "indeterminate form." What mathematicians mean
by "indeterminate form" is that in some cases we think about it as having one value, and in other
cases we think about it as having another. which is
slightly different than what ariels says. I guess
I think 1994 is recent, but the real discussion took place
in the 19th century...
However, read the link, don't let us read it for you.
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
However there is a valid question over what we should
get back from a computer when we calculate
00. If we are thinking in terms of doing an
exact calculation, then there is no question, there is
an answer we should give and that answer is 1. But if
we are thinking in terms of floating point math, then
what the computer should be designed in terms of is,
I have a number close to 0 raised to the power of
another number close to 0 and I need to give back
something that I know is close to the answer.
In that case the computer should give up because the real
answer might be anywhere between 0 and 1 inclusive.
Therefore of his examples, all of the answers make sense.
The two products which are designed to be working with
floating point extensively (ie Excel and his calculators)
think in terms of round-off error and decide that they
cannot give a reasonable answer. The remaining products
are all programming tools, dealing with integers, and
are assuming for one reason or another that they are dealing
with an exact integer calculation. So all of them give back
the answer 1.
(OK, I admit it, probably the calculators and Excel were
designed by people who remembered that 00 was
an indeterminate form but have no idea what that really
means. But there are calculational contexts in which
failing to give an answer in that case makes sense.)
| [reply] [Watch: Dir/Any] |
|
|
Re: More Fun with Zero!
by John M. Dlugosz (Monsignor) on Jul 24, 2001 at 00:31 UTC
|
If you multiply an inteterminte form by zero, it's like Unknown OR True being True no matter what the left side was. Anything times zero is zero, so NotSure * 0 is certainly zero.
So... Log 0 times 0 is zero, whatever we decide about the Log of zero. antilog of 0 is 1. So figuring out by the normal numeric methods, we get a result of 1 for 0**0.
Ah, but what is an antilog? We're back to 1**0 there. So, it's a tautology, but consistent!
Consistancy is the real point.
Take a graph of y=42**x for all real values of x. When x is 0.1, you get one and a half. For 0.01, 1.04. For 0.0001, you get 1.0004. Likewise for negative values of x. If you graph it, you see a big V pointing right at (0,1). If you zoom in, you find that out of all the infinite (second level infinite, yet!) points on the curve, *one* is missing. Yuck.
Now calculus deals with that all the time. You can't do it directly, but you can sneak up on it, finding the "limit" as x approaches zero. That's one of the reasons calculus was invented. So, it's definitly true that the limit as x approaches 0 of 42**x is zero.
What does that buy us? Like in programming, special cases are a pain. If in real work you tacidly assume you mean the limit, the work becomes a lot easier, and you get the right (useful?) answer anyway. Like I pointed out at the top, this produces consistant results when used in larger systems. So for all intents, n**0 is defined to be 1.
Now, do the same thing varying n. Draw the family of curves, and 42**x gives a V. 18**x gives a V with a different angle. .00000001 gives a nice V, too. All the curves in the family point to (0,1). What happens when n hits zero? BOOM! Again, take the limit and you get n**0 is 1 as n approaches arbitrarily close to zero.
| [reply] [Watch: Dir/Any] |
Re: More Fun with Zero!
by E-Bitch (Pilgrim) on Jul 23, 2001 at 19:43 UTC
|
Okay
Now you got me thinking. I have always been taught (as most of us have) that n^0 is 1. Now, why, do you suppose, that n multiplied by itself zero times, would it equal one? It isnt the same as n*0, I realize that, but if you think about n^1, you get n, right? meaning n^1=n. n^2=n*n, and n^0=? you dont have anything multiplied by anything else, so shouldnt this be undefined as well? I realize, also, that this has probably been defined by some dead mathematician who used this case to prove some wildy fantastic theorem, but still.
Am I totally off base with this?
thanks!
E-Bitch
p.s.:
my 2 cents about the 0^0 thing: 0^1 = 0 right? nothing multiplied by itself one time, should still equal nothing. so, if we were to think of this in terms of, oh, say, atoms, if you have no atoms muliplied by no atoms one time, you get no atoms (SURPRIZE!!!). now, if you have no atoms, multipled by no atoms, 0 times, you get 1 atom!
what?
we just created matter!
call the pentagon!
whoohoo!
note: energy to matter conversions do not apply in this simple example | [reply] [Watch: Dir/Any] |
|
Now you got me thinking. I have always been taught (as most of us have) that n^0 is 1. Now, why, do you suppose, that n multiplied by itself zero times, would it equal one?
It's a matter of consistency: remember, when you take two values which are exponents of the same base and multiply them together, you get that base, to the sum of the exponents. So, what is
((n)^1) * ((n)^-1) ?
It is n * (1/n) = (n/n) = 1.
This behaves politely for all real n != 0. But, it still remains 1 for all n->0 from each side, so it's what our friend in analysis call (and what tilly alluded to above) a removable singularity. That is, there is definitely a "hole" there, but for all-intents-and-purposes we can "plug" it when doing calculus.
Spud Zeppelin * spud@spudzeppelin.com
| [reply] [Watch: Dir/Any] |
|
The essence of the difficulty in this case is that defining a "consistent" value of the function f(x,y)=x^y isn't possible. By definition, x^y is defined as e^(y log x). (Which, incidentally, is itself not well-defined; one has to make a branch cut for log to have it make sense. If you don't know what that means, just assume that we've done it, as it doesn't really impact this discussion very much.) Note that the limit as x->0 (with y <> 0 fixed) is 0 and the limit as y->0 (with x <> 0 fixed) is 1. So we can't fill in a value at (0,0) that is going to make the function continuous there.
However, as others have noted, one can make a sensible convention 0^0=1 -- sensible in the sense that it makes doing certain things easier. There are other contexts in mathematics where one makes similar conventions (without sacrificing rigor, of course) in order to simplify notation or statements of results and so on. (E.g. in measure theory one might use the convention that 0 * infinity = 0.)
| [reply] [Watch: Dir/Any] |
Re: Division by Zero
by John M. Dlugosz (Monsignor) on Jul 24, 2001 at 00:43 UTC
|
I think you make a good case. As Perl 5 exists now, I can imagine a pragma being used to control this. Perhaps a special value for use warnings: the SV primitive would consult this warning value to decide whether to die, warn and return undef, or return undef silently.
In the future, with typed values and compiled code, it gets messy. SV-based generic code would return undef, integer code would hit a hardware exception unless it took pains to check every single divisor before doing it, which goes against the reason for compiling down to strongly-typed values.
One of the things I saw mentioned for Perl 6 is "Standardise Handling Of Abnormal Numbers Like Infinities And NaNs". See Perl RFC 38.
If division by zero returned not undef but a special known value representing the indeterminte form, it might get swollowed without ever causing a problem if you multipy by zero or something like that; or you get a suitable error later.
—John | [reply] [Watch: Dir/Any] |
Re: More Fun with Zero!
by lindex (Friar) on Jul 24, 2001 at 07:39 UTC
|
As far as the syntax for eval(EXPR);
I too like to make anything that can be one line accually
one line so I often use the evalution order of if
and do like:
#!/usr/bin/perl
use strict;
use warnings;
print qq(Hey no error !\n) if(eval(q(1;))&&!$@);
Brought to you by that crazy but lovable guy... lindex
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: More Fun with Zero!
by hsmyers (Canon) on Jul 24, 2001 at 18:12 UTC
|
Speaking only from the confines of my own narrow little mind, I really really don't like over loading undefined. It is far more useful at least for me, to deal with things like +/- infinity, NAN and other similar such. One of the first things I did when first using a math chip (AMD 9511 or AMD 9512) was to write the C to ASSM interface to handle errors and exceptions in general-- typically preserve and return the status word. More to the point, since there are a lot of ways to mess the math, I'd rather have more information than less!
just my 0.02$ worth
hsm
| [reply] [Watch: Dir/Any] |
Re: More Fun with Zero!
by Anonymous Monk on Jul 24, 2001 at 21:52 UTC
|
The correct answer is 1 and it is by definition!
Power is in fact a subcase of what is call the gama function
and in this more global definition you must have Gamma(0,0)=1 | [reply] [Watch: Dir/Any] |
|
You may be confused. The gamma function is unrelated to the function x^y. Perhaps you are thinking of the relationship Gamma(n+1) = n! for non-negative integers n. Moreover, Gamma(0) is undefined (as is, more generally, Gamma(n) for non-positive integers n).
(For those who are curious, the gamma function is most easily defined as the Gamma(x) = integral from 0 to infinity of e^(-t) * t ^ (x-1) dt. Google can pretty easily be convinced to take you to more information about it. But it's pretty much unrelated to the topic at hand.)
| [reply] [Watch: Dir/Any] |
|
|