Unsigned Multiplication using Signed Multiplier

808 views Asked by At

I have been assigned with a task to perform unsigned multiplication using signed multiplier. Despite multiple attempts, I couldn't get it. Is it possible to do this?

Code:

#include <stdio.h>
int main()
{
    // Must be short int
    short int a=0x7fff;
    short int b=0xc000;
    unsigned int res1;
    signed int res2;
    
    //unsigned multiplier
    res1= (unsigned short int) a * (unsigned short int) b;
    
    //signed multiplier
    res2= (short int) a * (short int) b;

    printf("res1: 0x%x %d \n res2: 0x%x %d\n",res1,res1,res2,res2);
    return 0;
}

This is the code provided.

Current Output:

res1: 0x5fff4000 1610563584 
res2: 0xe0004000 -536854528

Expected Output:

res1: 0x5fff4000 1610563584 
res2: 0x5fff4000 1610563584 

Working Code:

#include<stdio.h>
#include<conio.h>
int main()
{
    short int a = 0x7fff;
    short int b = 0x3000;
    unsigned int unsignedRes;
    signed int signedRes;
    unsigned int ourRes;
    // Unsigned Multiplier
    unsignedRes = (unsigned short int) a * (unsigned short int) b;
    // Signed Multiplier
    signedRes = (short int) a * (short int) b;

    // Our Code using SIgned Multiplier
    ourRes = ((short int)a & ~(0xffffu << 16))*((short int)b & ~(0xffffu << 16));

    printf("Expected: 0x%x\nSigned: 0x%x\nResult: 0x%x",unsignedRes,signedRes,ourRes);
    getch();
    return 0;
}
1

There are 1 answers

4
deamentiaemundi On

The assignment short int b=0xc000; alone is already implementation defined (vid.: ISO/IEC 9899:2018 6.3.1.3 p. 3) and would need to be done in two parts b = b1 * 2^15 + b0 = 0x1*2^15 + 0x4000 (assuming SHRT_MAX + 1 == 32768 ). If you do both in two parts like that and understand the assignment in such a way that the result is an unsigned data type and do a*b == (a1 * 2^15 + a0) * (b1 * 2^15 + b0) by using unsigned int ret2 for the result and signed int temporary variables for the rest.

Assuming that the input is restricted to the capabilities of an unsigned short int (unsigned because of 0xc000) and that all types must be signed types with the exception of the output:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(void)
{
   /*
      This whole thing has ben pulled apart for clarity and could (should!) be done
      in less lines of code.
      All implicit type conversions are made explicit.
      We also assume 2s complement (and a little bit more, to be honest).
    */

   /* 
       A and B limited to 0xffff to keep this code simple.
       If you want to get rid of these limits you need to count the bits
       of A and B and make sure that the sum does not exceed sizeof(int)*CHAR_BIT-1
    */
   signed int A = 0x7fff;
   signed int B = 0xc000;

   short int a0, a1;
   short int b0, b1;

   signed int shift = SHRT_MAX+1;

   unsigned int res1, res2;
   /* Additional temporary variables for legibility */
   signed int t0, t1, t2, t3;

   /* Check input range */
   if ((A > 0xffff) || (B > 0xffff)) {
      fprintf(stderr,"Input must not exceed 0xffff! A = 0x%x, B = 0x%x\n",A,B);
      exit(EXIT_FAILURE);
   }

   //unsigned multiplier
   res1 = (unsigned int)A * (unsigned int)B;

   //signed multiplier

   /* Compute  A*B == (a1 * shift + a0) * (b1 * shift + b0) */
   a0 = (short int)(A % shift);
   a1 = (short int)(A / shift);
   b0 = (short int)(B % shift);
   b1 = (short int)(B / shift);

   /*
      Multiply out for convenience:

      A*B == (a1 * 2^15 + a0) * (b1 * 2^15 + b0)
          ==  a1 * b1 *2^15 * 2^15
            + a0 * b1 * 2^15
            + a1 * b0 * 2^15
            + a0 * b0
    */
   /*
      Here a1 and b1 are either 0 (zero) or 1 (one) and (SHRT_MAX+1)^2 < INT_MAX
      so t0 cannot overflow.
      You should make use of that fact in production.
    */
   t0 = (signed int)a1 * (signed int)b1 * shift * shift; /* t0 in {0,shift^2} */
   t1 = (signed int)a0 * (signed int)b1 * shift; /* t1 in {0, a0 * shift} */
   t2 = (signed int)a1 * (signed int)b0 * shift; /* t2 in {0, b0 * shift} */
   t3 = (signed int)a0 * (signed int)b0; /* t3 can get larger than INT_MAX! */

   /* Cannot overflow because floor(sqrt(2^32-1)) = 0xffff and both A and B < 0xfff */
   res2 = (unsigned int)t0 + (unsigned int)t1 + (unsigned int)t2 + (unsigned int)t3;

   printf("res1: 0x%x %d\nres2: 0x%x %d\n",res1, res1, res2, res2);

   exit(EXIT_SUCCESS);
}

The assignment is rather under-defined, to keep it polite, but as I do not know if it is your fault, the teacher's fault or a bad zoom-connection I tried to give you a couple of directions. If it wasn't wat was expected you should at least be able to ask the right questions now.