signed vs. unsigned multiplication

Discussion in 'C Programming' started by wrschlanger, Jun 17, 2012.

  1. wrschlanger

    wrschlanger Guest

    Does anyone care to comment on the below program I wrote?
    The question I was wondering is: why do compilers still use IMUL or MUL forsigned or unsigned multiplication respectively when there is no differencein the numeric value of the result provided the product size is the same as the size of the two factors that are being multiplied together?

    This program prints PASS on my screen when I run it. Am I missing something?

    Here is what I think is going on. The Intel manual lists IMUL for signed imultiplication and MUL for unsigned. It does this because originally those instructions always doubled capacity, i.e. the product had twice the size ofthe factors.

    But then a variant of IMUL was introduced that discards the upper half of the result, i.e. it works like the C * operator. This is still listed as being for "signed" multiplication but it works equally well for unsigned multiplication and might be more efficient because it can take more operands.

    Do any compiler writers know about this?? Or do they blindly trust the Intel manuals?

    (By the way--interestingly I can't get (unsigned char)(0xff) to equal (signed char)(0xff) in GCC).
    #include <cstdio>

    int main()
    for(int a = 0; a < 256; ++a)
    for(int b = 0; b < 256; ++b)
    signed char sa = a;
    signed char sb = b;
    unsigned char ua = a;
    unsigned char ub = b;
    signed char sc = sa * sb;
    unsigned char uc = ua * ub;
    unsigned char usc = sc;
    if(uc != usc)
    std::printf("FAIL %02x * %02x = %02x vs. %02x\n", ua, ub, (unsigned int)(unsigned char)(sc), uc);
    return 0;
    wrschlanger, Jun 17, 2012
    1. Advertisements

  2. wrschlanger

    Xavier Roche Guest

    Le 17/06/2012 16:31, a écrit :
    There is no difference between signed/unsigned muls if you restrict them
    to the source size AFAIK.
    extern unsigned char mulu(unsigned char a, unsigned char b) {
    return a*b;

    extern signed char muls(signed char a, signed char b) {
    return a*b;

    $ gcc -O -S -std=c99 sample.c -o sample.S

    movl %esi, %eax
    imull %edi, %eax

    movl %esi, %eax
    imull %edi, %eax
    Xavier Roche, Jun 17, 2012
    1. Advertisements

  3. wrschlanger

    Eric Sosman Guest

    Comment: It's written in C++, not C. The two languages are
    related but not identical, and differ in details large and small.
    Try comp.lang.c++ for your C++ questions.
    This would be easy to explain in C, although I don't know whether
    the C++ explanation would be similar. In C on a machine with eight-bit
    characters, `signed char' cannot represent the value 0xFF=255 so the
    conversion of 255 to `signed char' so "the result is implementation-
    defined or an implementation-defined signal is raised." The usual
    implementation-defined result is just to store as many bits as will fit,
    which on a two's complement machine would produce -1. Meanwhile,
    `unsigned char' *is* able to hold 255, so your interesting observation
    is that 255 != -1; most people find this unsurprising.
    Eric Sosman, Jun 17, 2012
  4. First off, it's a C++ program and not a C one. I don't think there is a
    significant area of difference in this program, but if you want answers
    about C++ then comp.lang.c++ is a better place. It's possible that
    follow-ups might stray into and area where the is an important
    difference between the two languages.
    This is not really a C (or C++) question. You give a reasonable
    explanation below, but from a C point of view I wonder why you care. Do
    you think the compiler is getting something wrong as a result of the
    choice being made?
    Since you ask, the answer must be yes. Presumably you expected
    something else, but I can't be sure what. People here could offer more
    help if you say why you think you might be missing something.
    I would image that they trust the hardware documentation, but not
    "blindly". I feel I'm not really getting at what is bothering you.
    Well, there's something wrong with your expectation here. Whilst
    it's possible for these to be equal on some systems, it is not "normal"
    for the systems that have gcc ported to them.
    Change to stdio.h to make this a standard C header.
    In C, int main(void) is (marginally) better.
    Turn std::printf to plain printf to make this C.
    Ben Bacarisse, Jun 17, 2012
  5. wrschlanger

    wrschlanger Guest

    Hi Ben,

    I do a lot of low level stuff and regularly look at the output from my C compiler. (My apologies for posting C++ code to a C newsgroup).

    I was basically wondering about Visual C++ whose code seemed (at least for the old version I checked) to always use MUL for 32-bit unsigned multiplication, and I was wondering whether or not my observation that IMUL would work just as well, was accurate.

    This was answered by an earlier post, though I don't have a proof, I guess I don't need one as long as there's a general consensus -- and the fact that GCC generates identical code (using IMUL) is enough proof for me.

    The reason I made the post was because I was unaware that GCC did this.

    On Sunday, June 17, 2012 8:37:37 AM UTC-7, Ben Bacarisse wrote:
    Thanks for the tips on converting to C. If I have any other questions I will use a C++ newsgroup, or make sure everything works with plain C. Actuallythis question would have been better suited for an assembly group since it's specific to x86, but then they might complain I used C and not assembly :)

    wrschlanger, Jun 17, 2012
  6. wrschlanger

    BartC Guest

    I'm doing some code generation at the moment and using MUL and IMUL. If the
    latter works just as well, and could be faster because of the 32-bit, rather
    than 64-bit, result, then I will use it.

    Although the brief test I've just done shows no difference (not on my
    processor anyway).

    As for proof, testing that I get the same results on a selected range of
    values will do me. It's not necessary to test all 2**64 possible pairs of
    operands (and which would anyway take too long). And I wouldn't rely on the
    output of GCC; there could be many reasons why the generated code is what it
    BartC, Jun 17, 2012
  7. The (maligned) Intel manual[1] is actually reasonably clear about this,
    if you don't mind trusting it "blindly" for this occasion:

    "The two- and three-operand forms may also be used with unsigned
    operands because the lower half of the product is the same regardless if
    the operands are signed or unsigned. The CF and OF flags, however,
    cannot be used to determine if the upper half of the result is

    (When using the "correct" version of MUL/IMUL, the CF or OF flag -- they
    have the same value -- can be tested to see if any significant bits will
    be lost when truncating the result back to 32 bits, in case this is of

    [1] Intel(R) 64 and IA-32 Architectures Software Developer's Manual,
    Volume 2 (2A, 2B & 2C): Instruction Set Reference, A-Z: "IMUL--Signed
    Multiply", Vol. 2A, pp. 3-495.
    Heikki Kallasjoki, Jun 17, 2012
  8. wrschlanger

    Joe. Guest

    But you experience has no value.?

    It's not about programming anymore, it's about who you programmed for. ?

    I ask the hard questions. I should just shut up and capitalize on them?

    Did Jesus die for anyone's sins?
    Joe., Jun 25, 2012
  9. wrschlanger

    Joe. Guest

    Hi Ben,

    "I do a lot of low level stuff and regularly look at the output from my C
    compiler. (My apologies for posting C++ code to a C newsgroup)."

    But you don't want one of "dem jobs" either, huh? Did "your country" fail
    Joe., Jun 25, 2012
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.