1

I am trying to make a function that adds two numbers of any type (float, int, double etc), and saves the result into another number of the same type.

I was looking into void * and learned that by casting to unsigned char *, I can get each byte of each number.

The problem I am facing is, that when I add something greater than the range of an unsigned char, it wraps around. So in my case 255 + 1 = 0.

This my code so far,

typedef unsigned char byte;

// add two numbers (of any type) of size abc_size and save in c
void add(void *a, void *b, void *c, size_t abc_size) {
    byte *a_bytes = (byte *) a;
    byte *b_bytes = (byte *) b;
    byte *c_bytes = (byte *) c;

    for (size_t i = 0; i < abc_size; i++) {
        byte a_byte = a_bytes[i];
        byte b_byte = b_bytes[i];

        byte sum = a_byte + b_byte; // do i have to account for carry or endianess?
        c_bytes[i] = sum;
    }
}

and the main I used for testing,

#include <stdio.h>

int main(void) {
    int a = 255;
    int b = 1;
    int c = 0;

    add(&a, &b, &c, sizeof(int));

    printf("%d + %d = %d\n", a, b, c);
}

The output of the above is,

255 + 1 = 0

I am also facing a problem when I am trying to add floats or doubles, which the result is completely unexpected, and I would image is again because of the overflow.

Can this method work at all for any number and any type? If so, what do I need to change?

Thank you in advance.

loukritios
  • 101
  • 5
  • 4
    Just in advance: You cannot add floating point types byte by byte, so double and float are out anyway... – Aconcagua May 27 '23 at 23:28
  • 2
    Any particular reason you don't just add? – dbush May 27 '23 at 23:29
  • Have a look at [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) for how floating points are set up (well, actually not mandatory for C, but not aware of a single implementation not following...). – Aconcagua May 27 '23 at 23:31
  • Thank you @Aconcagua, I was not aware of that. – loukritios May 27 '23 at 23:32
  • @dbush For learning purposes strictly + I had a glimpse at how `memcmp` was implemented and was too curious:) – loukritios May 27 '23 at 23:33
  • *'Can this [...]'* – no, not for *any* – but for any integral, it does, provided you care for overflow. For unsigned you can easily detect, the sum will be smaller than any of the summands... – Aconcagua May 27 '23 at 23:35
  • There are very view big endian machines left out there at all any more – for these the approach in general works as well, **but** you need to transport the carry in opposite direction, i.e. you need to start adding at the *end* of the byte range. – Aconcagua May 27 '23 at 23:40
  • Yes, of course you have to take care of the carry. Don't declare `byte sum`. Use `int sum`. Then, if `sum > 255`, you've got a carry to take care of. – Steve Summit May 27 '23 at 23:45
  • 1
    By the way: Just of historical relevance – if at all, you'd find a non-two's complement machine only in some museum – but on such a machine you couldn't just add either if operating on signed integers ;) – Aconcagua May 27 '23 at 23:48

1 Answers1

4

You are trying to reinvent the wheel and your naive method will not work with any floating point numbers. use generic selection

#define add(a,b) _Generic((a), \
            double: addd, \
            default: addu,  \
            float:  addf,  \
            int: addi \
            )(a,b)


double addd(double a, double b)
{
    return a+b;
}

float addf(float a, float b)
{
    return a+b;
}

unsigned addu(unsigned a, unsigned b)
{
    return a+b;
}

int addi(int a, int b)
{
    return a+b;
}

int main(void)
{
    printf("%u %i %f\n", add(1u, 4u), add(-3,1), add(3.0, 1.5));
}

https://godbolt.org/z/T3nsdvKn1

0___________
  • 60,014
  • 4
  • 34
  • 74