2

I have a programming/math related question regarding converting between big endian and little endian and doing arithmetic.

Assume we have two integers in little endian mode:

int a = 5;
int b = 6;
//a+b = 11

Let's flip the bytes and add them again:

int a = 1280;
int b = 1536;
//a+b = 2816

Now if we flip the byte order of 2816 we get 11. So essentially we can do arithmetic computation between little endian and big endian and once converted they represent the same number?

Does this have a theory/name behind it in the computer science world?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Joe
  • 23
  • 2

3 Answers3

1

It doesn't work if the addition involves carrying since carrying propagates right-to-left. Swapping digits doesn't mean carrying switches direction, so any bytes that overflow into the next byte will be different.

Let's look at an example in hex, pretending that endianness means each 4-bit nibble is swapped:

int a = 0x68;
int b = 0x0B;
//a+b:  0x73

int a = 0x86;
int b = 0xB0;
//a+b: 0x136

816 + B16 is 1316. That 1 is carried and adds on to the 6 in the first sum. But in the second sum it's not carried right and added to the 6, it's carried left and overflows into the third hex digit.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
0

This only appears to work because you happened to pick numbers that are small enough so that they as well as their sum fit into one byte. As long as everything going on in your number stays within its respective byte, you can obviously shuffle and deshuffle your bytes however you want, it won't make a difference. If you pick larger numbers, e.g., 1234 and 4321, you will notice that it won't work anymore. In fact, you will most likely end up invoking undefined behavior because your int will overflow…

Apart from all that, you will almost certainly want to read this: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
0

First, it should be noted that your assumption that int in C has 16 bits is wrong. In most modern systems int is a 32-bit type, so if we reverse (not flip, which typically means taking the complement) the bytes of 5 we'll get 83886080 (0x05000000), not 1280 (0x0500)

Also note that you should write in hex to make it easier to understand because computers don't work in decimal:

int16_t a = 0x0005;
int16_t b = 0x0006;
// a+b = 0x000B

int16_t a = 0x0500; // 1280
int16_t b = 0x0600; // 1536
//a+b = 0x0B00

OK now as others said, ntohl(htonl(5) + htonl(6)) happens to be the same as 5 + 6 just be cause you have small numbers that their reverses' sum don't overflow. Choosing larger numbers and you'll see the difference right away


However that property does hold in ones' complement for systems where values are stored in 2 smaller parts like this case

In ones' complement one does arithmetic with end-around carry by propagating the carry out back to the carry in. That makes ones' complement arithmetic endian independent if one has only one internal "carry break" (i.e. the stored value is broken into two separate chunks) because of the "circular carry"

Suppose we have xxyy and zztt then xxyy + zztt is done like this

            carry
        xx        yy
      + zz <───── tt
      ──────────────
  carry aa        bb
     │             ↑
     └─────────────┘

When we reverse the chunks, yyxx + ttzz is carried the same way. Because xx, yy, zz, tt are chunks of bits of any length, it works for PDP's mixed endian, or when you store a 32-bit number in two 16-bit parts, a 64-bit number in two 32-bit parts...

For example:

  • 0x7896 + 0x6987 = 0xE21D
    • 0x9678 + 0x8769 = 0x11DE1 → 0x1DE1 + 1 = 0x1DE2
  • 0x2345 + 0x9ABC = 0xBE01
    • 0x4523 + 0xBC9A = 0x101BD → 0x01BD + 1 = 0x01BE
  • 0xABCD + 0xBCDE = 0x168AB → 0x68AB + 1 = 0x68AC
    • 0xCDAB + 0xDEBC = 0x1AC67 → 0xAC67 + 1 = 0xAC68

Or John Kugelman's example above: 0x68 + 0x0B = 0x73; 0x86 + 0xB0 = 0x136 → 0x36 + 1 = 0x37

The end-around carry is one of the reasons why ones' complement was chosen for TCP checksum, because you can calculate the sum in higher precision easily. 16-bit CPUs can work in 16-bit units like normal, but 32 and 64-bit CPUs can add 32 and 64-bit chunks in parallel without worrying about the carry when SIMD isn't available like the SWAR technique

phuclv
  • 37,963
  • 15
  • 156
  • 475