• AVR Freaks

16 bit multiply not working as expected

Author
rocketmagnet
Junior Member
  • Total Posts : 107
  • Reward points : 0
  • Joined: 2004/08/24 08:58:45
  • Status: offline
2011/01/21 05:17:50 (permalink)
0

16 bit multiply not working as expected

Hi all,

I wrote this code:

int16 a = 0x0100;
int16 b = 0x1000;
int32 c = a*b;

Now, c should be 0x100000. It certainly is when I compile this code on my PC. However, on the PIC18, using the MPLAB C18 compiler, the result is 0x00000000.

Is there a sensible and efficient way to perform a 16x16 multiplication and store the 32-bit result in a 32-bit variable?

Many thanks

Hugo

#1

7 Replies Related Threads

    ppater
    Super Member
    • Total Posts : 1002
    • Reward points : 0
    • Joined: 2006/08/26 10:33:06
    • Location: Ivry, France
    • Status: offline
    Re:16 bit multiply not working as expected 2011/01/21 05:33:29 (permalink)
    0
    This is basic: c = int32(a) * b;

    Best regards,
    Philippe.

    Pic Micro Pascal for All!
    #2
    rocketmagnet
    Junior Member
    • Total Posts : 107
    • Reward points : 0
    • Joined: 2004/08/24 08:58:45
    • Status: offline
    Re:16 bit multiply not working as expected 2011/01/21 05:59:14 (permalink)
    0
    This is basic: c = int32(a) * b; 



    I wouldn't be asking if this were basic.


    Look at the assembler this produces ... It contains the following call:


    CALL FXM3232, 0


    This is performing a 32bit x 32bit multiply, which takes considerably longer than a 16bit x 16bit multiply would. What I would like to do is a 16bit x 16bit multiply, storing the 32-bit result in a 32-bit variable. I do not want to promote it to a slower multiply.


    Hugo


    #3
    ppater
    Super Member
    • Total Posts : 1002
    • Reward points : 0
    • Joined: 2006/08/26 10:33:06
    • Location: Ivry, France
    • Status: offline
    Re:16 bit multiply not working as expected 2011/01/21 06:19:07 (permalink)
    0
    rocketmagnet
    Now, c should be 0x100000. It certainly is when I compile this code on my PC.

    It depends on your compiler and your native integer width.
    The rule is that both terms are promoted to at least the native integer format, that may be 16 bits, 32 bits , 64 bits or whatever is your native format on a PC. Your code may work on one machine and may not work on another one if you do not care of this.
    On a PIC, int native format is generally 16 bits, so by default the result is 16x16=>16.
    There's nothing that forces compilers to generate a code for the right expression according to the left (assigned) variable.
    AFAIK there's no direct 16x16=>32 multiply; it may be implemented in a library. I think this is the rule in most languages. But I'm not a specialist.
    That said, to make this in assembler for a PIC18 you need only a hand of instructions...



    Best regards,
    Philippe.

    Pic Micro Pascal for All!
    #4
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11286
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re:16 bit multiply not working as expected 2011/01/21 10:40:38 (permalink)
    0
    rocketmagnet

    int16 a = 0x0100;
    int16 b = 0x1000;
    int32 c = a*b;

    http://www.c-faq.com/expr/intoverflow1.html

    Is there a sensible and efficient way to perform a 16x16 multiplication and store the 32-bit result in a 32-bit variable?

    Not in any standard way.  Something like this might happen to work on C18:
    unsigned int b, c;

    union {
        struct {
            unsigned char b3, b2, b1, b0;
        } bytes;

        unsigned long result;
    } u;

    b * c;                              /* calls FXM1616U (16x16->32) */

    u.bytes.b0 = __AARGB0;
    u.bytes.b1 = __AARGB1;
    u.bytes.b2 = __AARGB2;
    u.bytes.b3 = __AARGB3;

    #5
    ErnieM
    Super Member
    • Total Posts : 375
    • Reward points : 0
    • Joined: 2007/10/13 02:54:02
    • Location: 0
    • Status: offline
    Re:16 bit multiply not working as expected 2011/01/21 12:57:25 (permalink)
    0
    ppater's points are well taken, especially his first point about casting to a 32 bit value.

    I tried several methods to see the problem under the C18 compiler. As long as neither a or b are cast as a 32 bit value the 32 bit result may be in error (zero).

     If *either* value (or both) are thus cast then c seemed to hold the correct value.

    This adds nothing to the point of doing the minimum amount of computation. For that, you may wish to write your own multiply routine. that way it would be compiler independent.
    post edited by ErnieM - 2011/01/21 13:12:03
    #6
    NKurzman
    A Guy on the Net
    • Total Posts : 17720
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re:16 bit multiply not working as expected 2011/01/21 18:48:21 (permalink)
    0
    That should be :
    c = (int32)a * b;
    c = a * b;   should assign the truncated lower 16 bits of the multiplication to c
    #7
    jtron
    New Member
    • Total Posts : 16
    • Reward points : 0
    • Status: offline
    Re:16 bit multiply not working as expected 2017/09/12 08:13:17 (permalink)
    +1 (1)
    The XC16 compiler has built-in functions for 16x16->32. For example, this will multiply two signed 16-bit values and produce a 32-bit signed result without any performance-killing promotions:
     
    int16 a = 0x0100;
    int16 b = 0x1000;
    int32 c = __builtin_mulss(a, b);
     
    Maybe similar functions are provided by your compiler.
    #8
    Jump to:
    © 2019 APG vNext Commercial Version 4.5