• (cs)

    What? n * (-1)?

    Most modern languages allow negation simply by prefixing the unary minus symbol to the value.

    int a = 1, b = 3;

    int c = (-a) * b;

    Why go through all the work of an explicit multiplication by negative one? I had to correct one of my developers on that point two weeks ago.

  • draeath (unregistered)

    More examples of what happens when you pay per line.

  • Vertu (unregistered)

    Why n*(-1), I think 0-n or simply -n would usually be faster and better operation.

  • (cs)

    -(Nice Code)

  • (cs) in reply to Vertu
    Vertu:
    Why n*(-1), I think 0-n or simply -n would usually be faster and better operation.

    Seems to me that both of those solutions have the same amount of operations in them as n*(-1)...I can't imagine where n*(-1) would be either less clear, or slower, than any other solutions...but then, maybe I missed the tongue being in the cheek on your comment...

  • (cs)

    To be fair, there is at least one case where simply "-n" won't quite work: maximum-magnitude negative integers in two's complement (e.g., "short i = -32768").

  • (cs) in reply to mrprogguy

    I think he wrote "n * (-1)" in the article, to make it really explicit that we are talking about negating numbers. If he had written "When '-n' won't do" the meaning would not have been as clear, imo.

    (btw, i really doubt that multiplying by -1 is any more work than using unary minus on any modern compiler. Whether it is more readable depends on the situation, but yeah i agree that usually unary minus is prettier)

  • Yuliy (unregistered)

    The second one looks like it takes the long way around taking a bitwise negation within the scope of a byte. The simple way around this is of course "return n ^ 0xFF".

  • barvins (unregistered) in reply to Voodoo Coder

    Multiplication is slow. At least on older processors it used to be much slower than subtraction. Of course, it only matters if you are doing processor-intensive stuff like raycasting.

  • barvins (unregistered) in reply to Voodoo Coder
    Voodoo Coder:
    Vertu:
    Why n*(-1), I think 0-n or simply -n would usually be faster and better operation.

    Seems to me that both of those solutions have the same amount of operations in them as n*(-1)...I can't imagine where n*(-1) would be either less clear, or slower, than any other solutions...but then, maybe I missed the tongue being in the cheek on your comment...

    Multiplication is slow. At least on older processors it used to be much slower than subtraction. Of course, it only matters if you are doing processor-intensive stuff like raycasting. (forgot to quote the stuff I was referring to)

  • (cs)

    I love the first one. It seems like he even got the basis of it - taking advantage of the fact that an undefined variable starts with a value of zero in VB6 - but didn't quite realize it.

  • Capt. Obvious (unregistered) in reply to Vertu
    Vertu:
    Why n*(-1), I think 0-n or simply -n would usually be faster and better operation.
    Well, keep in mind we're talking about doubles, not shorts/ints/etc. Thus, the first bit is a sign bit. Most efficent would be n^0x8000000000000000 (At least on a 64-bit machine.)
  • t604 (unregistered)

    Um... this smells like bullshit. Someone wrote the code just to submit it.

  • (cs) in reply to Yuliy
    Yuliy:
    The second one looks like it takes the long way around taking a bitwise negation within the scope of a byte. The simple way around this is of course "return n ^ 0xFF".

    Actually, the piece at the beginning expanding it to 8 bits will have no effect on the outcome (unless ConvertDecimal requires at least 8 digits) (If strBin is more than 8 characters, the rest will still work).

    The size independent method of taking the 1s compliment is "return ~n;"

  • (cs) in reply to barvins
    barvins:
    Multiplication is slow. At least on older processors it used to be much slower than subtraction. Of course, it only matters if you are doing processor-intensive stuff like raycasting. (forgot to quote the stuff I was referring to)

    Obviously multiplication will be faster then converting it to a string, doing comparisons and conversions on the like, then parsing it back to a number. With n*-1 (or preferably -n) you should only need 1 pass to get the new value. Shoot the difference between n and -n is usually 1 bit.

  • (cs) in reply to Capt. Obvious
    Capt. Obvious:
    Well, keep in mind we're talking about doubles, not shorts/ints/etc. Thus, the first bit is a sign bit. Most efficent would be n^0x8000000000000000 (At least on a 64-bit machine.)

    That assuming that your language/platform allows bitwise operations on floating point numbers (most do not). It also assumes that your cpu uses as it's internal format, the IEEE floating point exchange format (not a guarantee).

  • (cs)

    Comment * (-1)

    (Negative comment)

  • SpamBot (unregistered) in reply to t604
    t604:
    Um... this smells like bullshit. Someone wrote the code just to submit it.

    you must be new here ...

    </obligatory>
  • (cs)

    Why is poor nDec being ostracized that way? It's not good enough to be on the line with the others?

    int c,count,i; int nDec;

  • Shriike (unregistered)

    Wouldn't the second one not event work? If I had 0 (00000000) it would return -1 (11111111) so obviously he wasn't as stupid as we thought, he wasn't trying to just reverse the sign of a number, he was reversing the sign and then taking -1

    Captcha: opto (I enjoyed it)

  • Brillant Mathman (unregistered)

    Everyone knows the best and proper way to negate a number is

    n = n - 2*n;

    Nice and clear.

  • Bernie (unregistered) in reply to t604
    t604:
    Um... this smells like bullshit. Someone wrote the code just to submit it.
    Your comment smells like BS. I think you wrote it just to submit... errr... nevermind. Now that my brain is awake, I'd like to introduce the amazingly stupid recursive comment: this comment!
  • Bob Dole (unregistered)

    The real WTF is VB6.(Did I do that right?) In VB6, you can't return a value so you have to set the function equal to the value before exiting the function. I hate that BS "Function = Value" syntax. Functions aren't variables, cut that shit out.

    \You may hate on VB, but VB .Net made it so you can return, and you don't have the OnError logic crap. VB6 may be the devil. You can hate on VB, but VB6 is the real issue.

  • Kris (unregistered) in reply to t604
    t604:
    Um... this smells like bullshit. Someone wrote the code just to submit it.

    I'm guessing one of the above posters got it right. Whoever wrote that is being paid by the line.

  • iToad (unregistered)
    i = (i ^ 0xFFFFFFFF) + 1;

    Assuming:

    • All integers are 32 bits.
    • Two's complement integer storage.
    • Programming in C.
    • Error checking is for wimps.
  • (cs) in reply to mrprogguy

    Here's a neat code obfuscation technique:

    int i = 24742; int negative = 2323234;

    negative =- i;

    Or is it too easy to spot? :)

  • (cs) in reply to VibroKatana
    VibroKatana:
    Shoot the difference between n and -n is usually 1 bit.

    Shoot, it's not 1 bit, at least not in two's complement form. You'll find that ALL of the bits are flipped, and the sign bit is 1 instead of 0. I think.

  • sf (unregistered) in reply to Vertu
    Vertu:
    Why n*(-1), I think 0-n or simply -n would usually be faster and better operation.
    Well for one thing negation usually means change of sign, so 0-n would not work unless you knew n was always positive. -1 * n will always work. You are correct about -n, though, if your language supports it. Not all do.
  • Crash Magnet (unregistered) in reply to DWalker59
    DWalker59:
    VibroKatana:
    Shoot the difference between n and -n is usually 1 bit.

    Shoot, it's not 1 bit, at least not in two's complement form. You'll find that ALL of the bits are flipped, and the sign bit is 1 instead of 0. I think.

    n = (~n) + 1;

    Clear, n'est pas

  • Dave (unregistered) in reply to sf
    sf:
    Vertu:
    Why n*(-1), I think 0-n or simply -n would usually be faster and better operation.
    Well for one thing negation usually means change of sign, so 0-n would not work unless you knew n was always positive. -1 * n will always work. You are correct about -n, though, if your language supports it. Not all do.

    0 - -1 = 1, sign changed. 0 - 1 = -1, sign changed.

    where's the problem?

  • Dave (unregistered) in reply to Dave
    Dave:
    sf:
    Vertu:
    Why n*(-1), I think 0-n or simply -n would usually be faster and better operation.
    Well for one thing negation usually means change of sign, so 0-n would not work unless you knew n was always positive. -1 * n will always work. You are correct about -n, though, if your language supports it. Not all do.

    0 - -1 = 1, sign changed. 0 - 1 = -1, sign changed.

    where's the problem?

    In addition, 0 - n is faster for floating point than -1 * n is, in many cases...(premature optimization my ass)

  • Mitur Binesderti (unregistered)

    You guys are so negative...

  • (cs) in reply to sf
    sf:
    Well for one thing negation usually means change of sign, so 0-n would not work unless you knew n was always positive.

    Oh lord, please tell me you are joking. If you aren't, please tell me you are looking for a different line of work or at least are not anywhere near any code I am going to have to maintain in the future.

  • Fabien (unregistered)

    What a great language, it seems that "dblTempValue" is initialized by default with zero. And the author makes sure to make "dblTempValue - dblMagnitude" to confuse the reader

  • (cs) in reply to sf
    sf:
    Vertu:
    Why n*(-1), I think 0-n or simply -n would usually be faster and better operation.
    Well for one thing negation usually means change of sign, so 0-n would not work unless you knew n was always positive.

    I hope it was just a brainfart.

    0-(-5) = 0+5 = 5 0-(5) = -5

    See it now?

  • (cs) in reply to Dave
    Dave:
    Dave:
    0 - -1 = 1, sign changed. 0 - 1 = -1, sign changed.

    where's the problem?

    In addition, 0 - n is faster for floating point than -1 * n is, in many cases...(premature optimization my ass)
    Any reasonable compiler will reduce 0-n and (-1)*n and -n to a single-opcode floating point negation; with associated load/store iff the value is not in a FP register at given point.

    I have seen a cleverest compiler a while ago, which "knew" that a load/negate/store was slower on a particular architecture than handling it using integer mask and complement instructions. So, if the value couldn't be made to be in FP register (the compiler did instruction reordering), it'd relent and do it using integer opcodes. The difference was small (IIRC 2 clock cycles).

  • lesle (unregistered) in reply to barvins

    Well, multiplication is slower because it's actually repetitive addition, or at least it was 35 years ago on big iron. Likewise, division is repetitive substraction.

    Has that really changed?

  • clickey McClicker (unregistered)

    So does 0*-1 = -0 or just plain 0.

  • Franz Kafka (unregistered) in reply to clickey McClicker
    clickey McClicker:
    So does 0*-1 = -0 or just plain 0.

    Depends on the language. Some allow for a -0 that is !=0, while I think others use it as an init value that can be tested but is never produced by arithmetic.

  • Brad (unregistered)

    If I had to guess, I'd say that code was somebody's homework in a programming class.

  • (cs) in reply to t604
    t604:
    Um... this smells like bullshit. Someone wrote the code just to submit it.

    Ummm... this smells like bullshit. Someone wrote this comment just to say something.

    You must be new here. Go back and review other archived posts here. You'll see plenty of examples as bad as these (and some a lot worse).

  • Duke of New York (unregistered) in reply to t604
    t604:
    Um... this smells like bullshit. Someone wrote the code just to submit it.
    It seems reasonable to assume that you've never worked with outsourced code.
  • (cs) in reply to lesle
    lesle:
    Well, multiplication is slower because it's actually repetitive addition, or at least it was 35 years ago on big iron. Likewise, division is repetitive subtraction. Has that really changed?

    Yes, it really has. Multiplication and division are fixed time, single cycle operations on most CPUs now (really, since about 1990 or so). Unless you're programming an 8-bit microcontroller, it's nearly always faster to do things the obvious way, rather than the "clever" way.

    On a pipelined, superscalar CPU (i.e. most desktop/server systems), load & store time and cache behavior have much more effect on performance than using multiply vs bit-shifting, for example.

  • ciph3r (unregistered)

    You're all wrong! shakes head over-complicating! mumbles to self

    dblVal = val * 2; for(int i=0;i<dblVal;i++) val--;

    THERE!

  • (cs) in reply to DaveAronson
    DaveAronson:
    To be fair, there is at least one case where simply "-n" won't quite work: maximum-magnitude negative integers in two's complement (e.g., "short i = -32768").

    No other alternative will work here either, mainly because it can't be done. Now, "-n" will create an overflow error, that your program will ignore anyway, since you are not coding in assembly.

    Also, for the others, there is no speed difference on integer addition and multiplication on consumer-grade hardware since the 486, there is no difference for floating point for a wile either. Also, about floating point, most compilers will turn "-n" into a bit flipping anyway, it will probably also work for "0 - n" and "-1 * n", altough it simply can't deal with very "smart" constructions.

  • Shmork (unregistered)

    First rule of programming: no matter how WTF a piece of code is, there will always be someone to defend it.

  • harry (unregistered) in reply to sf
    sf:
    Well for one thing negation usually means change of sign, so 0-n would not work unless you knew n was always positive.
    Since people complained about this:
    $ cat negzero.c
    #include <stdio.h>
    int main(void) {
      printf("%g\n", 0 - 0.);
      printf("%g\n", -1 * 0.);
      return 0;
    }
    $ c89 negzero.c -o negzero
    $ ./negzero
    0
    -0
  • Steve H. (unregistered) in reply to Mcoder
    Mcoder:
    Also, for the others, there is no speed difference on integer addition and multiplication on consumer-grade hardware since the 486
    Not if you program on small embedded processors that don't have a multiply instruction (or take much longer to multiply than divide).
  • Dirk Diggler (unregistered) in reply to Shmork
    Shmork:
    First rule of programming: no matter how WTF a piece of code is, there will always be someone to defend it.
    I thought we weren't supposed to talk about it.
  • hcs (unregistered) in reply to harry

    for what little it may be worth:

    $ cat negzero.c
    #include <stdio.h>
    int main(void) {
        double i = 0 - 0.;
        double j = -1 * 0.;
        printf("%g\n", i );
        printf("%g\n", j );
        if ( i == j ) printf("i == j\n");
        if ( i == 0 ) printf("i == 0\n");
        if ( i == 0. ) printf("i == 0.\n");
        if ( j == 0 ) printf("j == 0\n");
        if ( j == 0. ) printf("j == 0.\n");
        if ( i < 0 ) printf("i < 0\n");
        if ( i < 0. ) printf("i < 0.\n");
        if ( j < 0 ) printf("j < 0\n");
        if ( j < 0. ) printf("j < 0.\n");
        return 0;
    }
    $ c89 negzero.c -o negzero
    $ ./negzero 
    0
    -0
    i == j
    i == 0
    i == 0.
    j == 0
    j == 0.
    

    Some of the comparisons are redundant as the 0 is promoted to 0. anyway. I don't know what how much of this is processor-dependent, compiler-dependent, or specified by the C standard. And this is why I hate floating point. (also boo for bonus newlines)

Leave a comment on “Classic WTF: The Challenges of Negation”

Log In or post as a guest

Replying to comment #:

« Return to Article