0

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;
}
fatalcoder524
  • 1,428
  • 1
  • 7
  • 16
  • 1
    It's not clear what the constraints are. Are you allowed to use signed 32-bit multiplication? Or can you use multiple smaller multiplications? What are the rules? – Tom Karzes Oct 15 '20 at 16:37
  • The only thing given is to use the signed multiplier and do an unsigned multiplication. And this code which shows what a signed multiplier is. We are allowed to modify the multiplier but not to perform any unsigned multiplication. @TomKarzes Sorry, If I cant be more clear. – fatalcoder524 Oct 15 '20 at 16:57
  • But since the only constraint is not to use the unsigned multiplier, I think it's allowed to do multiple small calculations. – fatalcoder524 Oct 15 '20 at 17:02
  • One approach is to cast both operands to `int`. If `int` is 32 bits on your machine, then that will work for a lot of cases. However, the result could overflow if it's >= 2**31. You could use `unsigned long long` which, if it's 64 bits, would let you obtain the correct result. But even then, if you try to cast it to `int`, which seems to be a constraint of the problem, it could overflow. The worst possible case is multiplying `0xffff` by `0xffff`. The result should be `0xfffe0001`, which cannot be represented as a signed 32-bit integer. It can be represented as an unsigned 32-bit value. – Tom Karzes Oct 15 '20 at 17:44
  • So it's not clear how you want to handle that case. – Tom Karzes Oct 15 '20 at 17:45
  • The program causes undefined behaviour by using incorrect format specifiers (`%d` can only be used for signed int, and `%x` only for unsigned int) – M.M Oct 16 '20 at 03:30
  • @M.M I'm just using `%d` just to understand the problem using normal number system. – fatalcoder524 Oct 16 '20 at 05:26
  • @fatalcoder524 use `%u` for unsigned int base 10 – M.M Oct 16 '20 at 05:33
  • @M.M Sure. Thank you! – fatalcoder524 Oct 16 '20 at 05:34

1 Answers1

1

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.

deamentiaemundi
  • 5,502
  • 2
  • 12
  • 20
  • Thank you very much. You saved me. I was also thinking of something similar, but couldn't find a way to split it. – fatalcoder524 Oct 16 '20 at 03:25
  • I noticed you used `short int a0, a1,b0,b1` but after using `unsigned short int a0, a1,b0,b1`. It fixed my problem. – fatalcoder524 Oct 16 '20 at 06:29
  • 1
    @fatalcoder524 yes, that would have fixed your problem (and that's how you would do it in the first place. Allows you to e.g.: use bit-wise operations which are a huge advantage on its own) but your assignment was to use **signed** types? – deamentiaemundi Oct 16 '20 at 13:48
  • The assisgnment was, in a system where you can only do signed multiplication, how do you get the answer of unsigned multiplication using signed multipler. – fatalcoder524 Oct 17 '20 at 01:40