Shop OBEX P1 Docs P2 Docs Learn Events
-0 < 0 ? — Parallax Forums

-0 < 0 ?

Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
edited 2008-06-16 17:35 in Propeller 1
I've discovered that, in Spin, $8000_0000 < 0 is true. So is -$8000_0000 < 0, as is || $8000_0000 < 0. $8000_0000 is that peculiarity of two's complement arithmetic that has a "value" of either 0, "-0", or -2147483648, depending on one's interpretation. (TV_Text prints is as "-0"; but, when entering "-0" in Spin, you get zero, of course, not $8000_0000). In my own programming, I've sometimes used $8000_0000 to represent "undefined", when it cannot be arrived at naturally.

On the one hand, this property of Spin can certainly be useful as a quick test for the sign bit, and I'm glad the interpreter doesn't waste cycles testing for this special case. On the other hand, I wonder if there are any, more purely mathematical, apps depending on Spin's purportedly signed arithmetic that could get in trouble because of it.

I've also noticed that the compiler gladly accepts 2147483649 ($8000_0001 in unsigned arithmetic) as a valid decimal number, which TV_Text prints as -2147483647. While it's plain that hex constants should be treated by the compiler as "sign-agnostic", I wonder, given that Spin uses signed arithmetic exclusively, whether an invalid decimal constant should be flagged with an error or warning. This stems from the fact that, when using hex constants, one is acknowledging a certain internal representation. With decimal constants, those details are hidden from view and easily overlooked by the unwary.

Whatever the case, these are the kinds of things CS students are trained to look out for when programming. I'm not necessarily unhappy with the way Spin handles (or ignores) these issues. But it pays to know (and be reminded occasionally) that they exist.

-Phil

Comments

  • RaymanRayman Posts: 14,162
    edited 2008-06-13 18:22
    I think it's one's compliment that has 2 forms of 0... Two's compliment just has one zero.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-06-13 18:35
    Technically, you're correct. In 32-bit ones complement arithmetic, $FFFF_FFFF == -0. But in twos complement arithmetic, $8000_0000 can get interpreted as 0 (i.e. its own negative, an exclusive property of zero), or even as -0 (as TV_Text does), depending on how this special case is handled (or not handled).

    Also, "sign-magnitude" arithmetic has a -0, which happens to be $8000_0000 (32-bit).

    -Phil

    Post Edited (Phil Pilgrim (PhiPi)) : 6/13/2008 6:40:51 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2008-06-13 18:38
    In two's complement 32-bit arithmetic, $8000_0000 is a negative number and there is no equivalent positive number, so -$8000_0000 and || $8000_0000 are meaningless. If the compiler had any provisions for warning messages, these cases would be candidates for one, but it only has provisions for fatal errors.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-06-13 18:49
    Mike,

    Again, technically correct. I suppose if anything needs to change, it's probably TV_Text.

    I plan to make that change in a subsequent version of TV_WText. I've also added a modified version of your broadcast video settings to it and am working on adding a provision for broadcast sound (and muting to eliminate the white noise when broadcasting video without sound). To do the latter, I needed to write some unsigned arithemetic routines in Spin, which is where all this got started.

    -Phil
  • RaymanRayman Posts: 14,162
    edited 2008-06-13 23:26
    Phil: I had to read this a couple times to see what you mean! Definitely a bug with TV_Text if it prints $8000_0000 as -0.
  • Mike GreenMike Green Posts: 23,101
    edited 2008-06-14 00:24
    It's not just TV_Text. All of the ".dec" routines use the same basic logic. They test for a negative number and output a "-" if so (and take the two's complement of the decimal value). Then they do the conversion to decimal using successive divisions by powers of ten.

    The main question is whether it's important enough to add extra code to check for the special case of $8000_0000 and output the appropriate string constant. Since "-0" will only be produced in the case of $8000_0000, that is actually a legitimate representation for the $8000_0000 in decimal and maybe nothing has to be changed except maybe a comment in the source code to that effect.
  • Ken PetersonKen Peterson Posts: 806
    edited 2008-06-14 16:18
    I think we're missing the point here. As a signed long, $8000_0000 is -$8000_0000, not -0. Signed bytes range from -128(-$80, represented as $80 in 2's compliment) to +127($7F). Signed longs range from -$8000_0000 to $7FFF_FFFF. If a function prints a signed long value of $8000_0000 as -0, that is just plain wrong, because it should be -2,147,483,648 (decimal). $8000_0000 is within the valid range for a signed long. If one cannot accept $80 being printed as -0, then one should not accept $8000_0000 being printed as -0. Like Rayman said: 2's compliment has only one zero and $8000_0000 is not a valid representation of zero.

    || $8000_0000 < 0 is also incorrect. I imagine SPIN interprets it that way because the correct result cannot be represented as a 32-bit long. ||-$8000_0000 == +$1_0000_0000. 2's compliment is not symmetrical, so we have this special case for absolute value. In my opinion, SPIN should recognize this case and represent || $8000_0000 as being equivalent to zero, not < 0, since $1_0000_0000 represented as a long is 0.

    But then again...the SPIN interpreter uses all available space in the cog, so a correction for this would be wishful thinking. As a result: "caveat codor" (let the programmer beware). smilewinkgrin.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔


    Post Edited (Ken Peterson) : 6/14/2008 5:03:08 PM GMT
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-06-14 17:30
    I'm not sure it's desirable — or even possible to "fix" this in Spin: undesirable, if ithe additional checks slow execution; impossible (for now), if it's embedded in the interpreter. The behavior is the result of performing the simplest test for negativity, i.e. checking the sign bit. It's just something that programmers have to be aware of.

    As to fixing tv_text and other ".dec"-infested objects, I'm coming around to Mike's way of thinking: it's probably not worth the effort, so long as programmers are made aware of the anomaly.

    In any event, number representations can mean pretty much whatever we — or the programming languages we use — say they mean, even if it runs against convention. If I were designing a computer language, I'd be tempted to let $8000_0000 mean "undefined" and initialize all variables to that "value". It's what could be also be returned by things like x/0, tan(90), etc. But for now, I'm content with the way Spin handles things, so long as it's documented.

    -Phil
  • hippyhippy Posts: 1,981
    edited 2008-06-14 18:22
    I think the only issue / error is in the way .dec() methods works. It's a display / conversion problem rather than a number representation problem. I've been caught out by -0 as well.

    What Abs and Negate $8000_0000 should do is open to debate but returning $8000_0000 seems reasonable and consistent with other implementations I've experienced and that's what appears to be happening in the example cases given earlier.
  • Jeff MartinJeff Martin Posts: 756
    edited 2008-06-16 16:56
    Hi,

    Just so everyone knows, the Propeller's hardware is doing exactly what it was designed to do in this case.· It's not how Spin is interpreting it, it's not the fault of Spin's || operator implementation... the Propeller Assembly ABS instruction returns the same value.· It's simply being deterministic and returning the result in the same way it always does but, user-interpretation aside, in 2's compliment this happens to be the exception case·where there is no positive compliment, so the result in the smallest negative number possible in the given bit space.· If the same logic were applied to a 33-bit value, $8000_0000 would be positive, but $1_0000_0000 would be·the exception case.

    TV_Text·has a minor bug in this respect as it's number·to string conversion method doesn't take this exception into consideration.···By the way, the Numbers object does convert this properly, but it also has a lot more code to provide many other conversion features that we're never intended for inclusion in the TV_Text object.



    Take care,

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Jeff Martin

    · Sr. Software Engineer
    · Parallax, Inc.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-06-16 17:35
    Jeff, I agree that there really isn't a problem here. I fear that I started a tempest in a teapot with this thread and kinda regret my original post.

    I think we can all agree that $8000_0000 has some weird properties:

    1. It's its own negative (uniquely a property of zero in unbounded arithmetic).

    2. Its absolute value is negative (a property of no number in unbounded arithmetic).

    3. It's a negative number that, when decremented by one, becomes a large positive number (a property of no number in unbounded arithmetic).

    We're not dealing in unbounded arithmetic but, rather, modular arithmetic, whose characteristics diverge from "real math" at the modular boundary. Frankly, I don't think it matters what we call $8000_0000, be it "-2147483648", "-0", "0", or "undefined". It's not a real integer, so we shouldn't expect it to behave like one. Consequently, I wouldn't even call its tv_text representation a "bug" necessarily, since "-0" (though at odds with convention) is as consistent with the math as anything else one could output.

    Move along, folks. 'Nothing to see here. smile.gif

    -Phil
Sign In or Register to comment.