-1

I have been given this problem and would like to solve it in C:

Assume you have a 32-bit processor and that the C compiler does not support long long (or long int). Write a function add(a,b) which returns c = a+b where a and b are 32-bit integers.

I wrote this code which is able to detect overflow and underflow

#define INT_MIN     (-2147483647 - 1) /* minimum (signed) int value */ 
#define INT_MAX       2147483647    /* maximum (signed) int value   */  

int add(int a, int b)
{

    if (a > 0 && b > INT_MAX - a) 
    {
        /* handle overflow */
        printf("Handle over flow\n");
    } 
    else if (a < 0 && b < INT_MIN - a) 
    {
        /* handle underflow */
        printf("Handle under flow\n");
    }
    return a + b;
}

I am not sure how to implement the long using 32 bit registers so that I can print the value properly. Can someone help me with how to use the underflow and overflow information so that I can store the result properly in the c variable with I think should be 2 32 bit locations. I think that is what the problem is saying when it hints that that long is not supported. Would the variable c be 2 32 bit registers put together somehow to hold the correct result so that it can be printed? What action should I preform when the result over or under flows?

M.M
  • 138,810
  • 21
  • 208
  • 365
DonRobb
  • 57
  • 4
  • 1
    Please note how your question looks while writing it. Mark code as code so it actually looks reasonable. I've fixed it for now, but do take note of it. – Sami Kuhmonen Sep 19 '15 at 15:02
  • Everything you're asking is completely implementation-specific. – Jonathon Reinhart Sep 19 '15 at 15:03
  • 2
    `INT_MAX` macro is already present in `limits.h` you don't need to do that yourself . Just include the header . – ameyCU Sep 19 '15 at 15:03
  • This is actually a mathematica problem you are asking for.First solve that one, then try to implement. – too honest for this site Sep 19 '15 at 15:06
  • All compilers must support `long int` – M.M Sep 19 '15 at 15:06
  • 2
    @M.M Not if the professor writing the problem decides it can't. – Carey Gregory Sep 19 '15 at 15:09
  • You have some decisions to make — notably, how you are going to store/return the 'long' value. There's a reason the standard enforces the 'usual arithmetic conversions' — it makes life easier. At issue for you is whether your function returns an `int` or whether it returns something else, and if it is something else, what else. You then need to deal whether the arguments should be the same type as the result. And most things fall into place from those explicit decisions. – Jonathan Leffler Sep 19 '15 at 15:09
  • 2
    The point is probably to do multiword addition. This whole overflow business is a completely different direction that your problem didn't ask for. – harold Sep 19 '15 at 15:10
  • Thanks for comments. I realize it is implementation specific. I am using Visual Studio 2012 express Win32 app. I have also been instructed to not use math libraries so I moved the defines out of limits.h.. I really think what the problem is asking is how to store the result properly using two 32 bit variables . Would some be able to show me how to do that? – DonRobb Sep 19 '15 at 15:15
  • @CareyGregory such a compiler would not be a C compiler – M.M Sep 19 '15 at 15:21
  • I think harold has is right. I'm not sure how to do the multi word addition properly and I may confusing the issue with overflow and underflow. I just thought that this would be a way or signal to preform some action to do multi word addition properly and store the result properly in two 32 variables but I am not sure how to do it if the variables I am adding are only 32 bits? – DonRobb Sep 19 '15 at 15:22
  • @M.M It's a test question. The tester can make up any rules he likes and a student's pedantic objections about what constitutes a C compiler would likely be met with rolling eyes. – Carey Gregory Sep 19 '15 at 15:27
  • @CareyGregory People can say whatever they want, sure – M.M Sep 19 '15 at 15:29
  • Return a struct of two ints. As for the problem, since it's a problem with no efficiency issue, break down the 2 x 32 bits values in 2 64 char arrays (you don't need that much, but this is easier to visualize), and perform the operation char to char into a 3rd 64 char array, one by one as if they were bits. Think about negative numbers (assuming 2's complement). Then build a 2 ints struct, with a MSW (most significant word) and LSW. Use the >> and << binary operators. – Déjà vu Sep 19 '15 at 15:33
  • @M.M Well, your instructor can, and your inability to recognize a thought problem for what it is would most likely result in a negative impact on your grade in the course. – Carey Gregory Sep 19 '15 at 15:33
  • 2
    @M.M: If you don't like 'no long', assume that the question is for 128-bit integers being simulated on a machine with no more than 64-bit registers. Asking how to cope with the absence of a feature is a legitimate way of making people think about how the feature is implemented. I think your attitude here is 'not constructive'. – Jonathan Leffler Sep 19 '15 at 15:36

2 Answers2

2

Since this is a homework question I'll try not to spoil it completely.

One annoying aspect here is that the result is bigger than anything you're allowed to use (I interpret the ban on long long to also include int64_t, otherwise there's really no point to it). It may be temping to go for "two ints" for the result value, but that's weird to interpret the value of. So I'd go for two uint32_t's and interpret them as two halves of a 64 bit two's complement integer.

Unsigned multiword addition is easy and has been covered many times (just search). The signed variant is really the same if the inputs are sign-extended: (not tested)

uint32_t a_l = a;
uint32_t a_h = -(a_l >> 31);  // sign-extend a
uint32_t b_l = b;
uint32_t b_h = -(b_l >> 31);  // sign-extend b
// todo: implement the addition
return some struct containing c_l and c_h

It can't overflow the 64 bit result when interpreted signed, obviously. It can (and should, sometimes) wrap.

To print that thing, if that's part of the assignment, first reason about which values c_h can have. There aren't many possibilities. It should be easy to print using existing integer printing functions (that is, you don't have to write a whole multiword-itoa, just handle a couple of cases).

As a hint for the addition: what happens when you add two decimal digits and the result is larger than 9? Why is the low digit of 7+6=13 a 3? Given only 7, 6 and 3, how can you determine the second digit of the result? You should be able to apply all this to base 232 as well.

harold
  • 61,398
  • 6
  • 86
  • 164
  • Please spoil it harold. I think this may be the best answer yet. I am so thankful that you see the problem correctly – DonRobb Sep 19 '15 at 15:49
  • @DonRobb that's dangerous you know, what if your teacher finds this? It's not that hard even, you know how it works in base 10 already, the only difference is the base – harold Sep 19 '15 at 15:53
  • I think it would be ok. I have done this type of the thing before. I am to use the tools of the world by any means so that I understand. I do think I know what you are getting at though and appreciate your help for sure. I just have to do the addition and use the carry I think because the base is 2. I do intend to go and play with what you have provided. I still would love to see how you do since your only one who gets it. please please pretty please. – DonRobb Sep 19 '15 at 16:03
  • @DonRobb the thing is how you know when there's a carry. That's a very simple condition that you actually already know in base 10, but you probably don't even think about it because base 10 seems so natural. – harold Sep 19 '15 at 16:08
  • I think the trick is to xor the bits then xor the result with a carry flag and if they are the same and two bits in that operation are 1 then there is a carry. – DonRobb Sep 19 '15 at 16:18
  • @DonRobb I don't know, maybe, but it doesn't sound familiar. the answer is an other answer now anyway – harold Sep 19 '15 at 16:21
  • Thanks Harold If I can't figure out how to do binary arithmetic I'll post another question lol. I am very grateful you helped me – DonRobb Sep 19 '15 at 16:25
  • This is a great answer didactically, +1. It's also a nice puzzle for this saturday afternoon, so I couldn't resist coding up an implementation for the unsigned case. Fortunately, the signed implementation requires some more hacking, so @DonRobb still has work to do. :) – user4815162342 Sep 19 '15 at 16:28
  • A big thanks to Harold for understanding the problem and helping me. This is my solution. I would like to post it for the world to see!!! I would also invite anyone to poke holes in it if they can. I've tested it using a bunch of signed numbers. I have been comparing the results with a 64 programming calculator and viewing the hex/binary values I get. It seems to work but you just never know unless you build a test for all cases. – DonRobb Sep 22 '15 at 15:21
  • struct Var64Bit { unsigned int uLowWord; unsigned int uHiWord; }; – DonRobb Sep 22 '15 at 15:23
  • Var64Bit add(int a, int b) { Var64Bit A; Var64Bit B; Var64Bit C; unsigned int uLoCarry; unsigned int uHiCarry; A.uLowWord = a; A.uHiWord = -(A.uLowWord >> 31); // sign-extend a B.uLowWord = b; B.uHiWord = -(B.uLowWord >> 31); // sign-extend b // Iterate till there is no carry while (!((B.uLowWord == 0) && (B.uHiWord == 0))) { uLoCarry = A.uLowWord & B.uLowWord; uHiCarry = A.uHiWord & B.uHiWord; A.uLowWord = A.uLowWord ^ B.uLowWord; A.uHiWord = A.uHiWord ^ B.uHiWord; B.uLowWord = uLoCarry << 1; – DonRobb Sep 22 '15 at 15:25
  • if(uLoCarry & 0x80000000) { B.uHiWord |= 0x0001; } } return A; } – DonRobb Sep 22 '15 at 15:27
0

First, the simplest solution that satisfies the problem as stated:

double add(int a, int b)
{
  // this will not lose precision, as a double-precision float
  // will have more than 33 bits in the mantissa
  return (double) a + b;
}

More seriously, the professor probably expected the number to be decomposed into a combination of ints. Holding the sum of two 32-bit integers requires 33 bits, which can be represented with an int and a bit for the carry flag. Assuming unsigned integers for simplicity, adding would be implemented like this:

struct add_result {
  unsigned int sum;
  unsigned int carry:1;
};

struct add_result add(unsigned int a, unsigned int b)
{
  struct add_result ret;
  ret.sum = a + b;
  ret.carry = b > UINT_MAX - a;
  return ret;
}

The harder part is doing something useful with the result, such as printing it. As proposed by harold, a printing function doesn't need to do full division, it can simply cover the possible large 33-bit values and hard-code the first digits for those ranges. Here is an implementation, again limited to unsigned integers:

void print_result(struct add_result n)
{
  if (!n.carry) {
    // no carry flag - just print the number
    printf("%d\n", n.sum);
    return;
  }
  if (n.sum < 705032704u)
    printf("4%09u\n", n.sum + 294967296u);
  else if (n.sum < 1705032704u)
    printf("5%09u\n", n.sum - 705032704u);
  else if (n.sum < 2705032704u)
    printf("6%09u\n", n.sum - 1705032704u);
  else if (n.sum < 3705032704u)
    printf("7%09u\n", n.sum - 2705032704u);
  else
    printf("8%09u\n", n.sum - 3705032704u);
}

Converting this to signed quantities is left as an exercise.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • I'm really not thinking the prof wants me to use floating point. I really don't think that is what the problem is asking. I appreciate the response is an honest attempt to help. – DonRobb Sep 19 '15 at 15:33
  • I see the humor and am tickled inside but I wonder if my professor will see the humor the way we do? – DonRobb Sep 19 '15 at 15:41
  • I'm guessing some dv may be due to the incorrect assessment that - due to the nature of double - there are some precision issue. There are none, here. – Déjà vu Sep 19 '15 at 15:41
  • 1
    @DonRobb I would start with this answer as simplest and then proceed with the "real" one. In this case the problem seems under-specified because it's unclear what type `add` is allowed to return, exactly. Sure, you can return a `struct` of two ints (and I can write up an answer that does it), but that's not very useful. Are you sure `add` is not supposed to **print** the numbers or something like that? – user4815162342 Sep 19 '15 at 15:48
  • Why not the usual `sum < a`? – harold Sep 19 '15 at 16:18
  • @DonRobb Here is an implementation of the method from harold's answer, limited to unsigned integers for simplicity (and to leave the rest to you:)). – user4815162342 Sep 19 '15 at 16:18
  • @harold `sum < a` would work fine here, it's just that I started with the signed case in mind. – user4815162342 Sep 19 '15 at 16:19