Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

More Fun with Zero!

by CheeseLord (Deacon)
on Jul 23, 2001 at 11:48 UTC ( [id://98931]=perlmeditation: print w/replies, xml ) Need Help??

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:

  • In MS Excel, trying the formula '=0^0' will return a #NUM! error.
  • With the Windows Calculator, "0, x^y, 0" results in an answer of 1.
  • With two personal calculators, the expression results in an error.
  • In C, math.h's "pow(0,0)" returns 1.
  • In Python (not that it matters at all ;-), "0 ** 0" returns 1.
  • In Java, Math.pow(0,0) also returns 1.
  • And with Perl...
     
    % perl -le 'print 0**0'
    1
    

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

Replies are listed 'Best First'.
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.

      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

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.

      Yea, Combinatorics should be much more interesting to the layman than Calculus. It was invented so that he could be a better poker player!
      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.

        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...

        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")
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.

      The FAQ starts by stating 00 is what's known in calculus as an "indeterminate form", which makes sense for calculus, since xy isn't continuous at x=0,y=0. It then goes on to say:
      Other than the times when we want it to be indeterminate, 0^0 = 1 seems to be the most useful choice for 0^0 . This convention allows us to extend definitions in different areas of mathematics that would otherwise require treating 0 as a special case.
      It then gives a list of reasons why 1 is such a good choice.

      It does not mention any recent discussion.

        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.)

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.

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

      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

        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.)

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

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
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
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

      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.)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://98931]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2024-03-19 02:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found