Листать байты, делать арифметику и снова переворачивать их - PullRequest
2 голосов
/ 30 апреля 2019

У меня есть вопрос по программированию / математике, касающийся преобразования между старшим и младшим порядковыми числами и выполнения арифметики.

Предположим, у нас есть два целых числа в режиме с прямым порядком байтов:

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

Давайте перевернем байты и добавим их снова:

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

Теперь, если мы изменим порядок байтов 2816, мы получим 11. Таким образом, по существу, мы можем выполнять арифметические вычисления между прямым и прямым порядком байтов, и после преобразования они представляют одно и то же число?

Есть ли в мире информатики теория / название?

Ответы [ 3 ]

1 голос
/ 30 апреля 2019

Не работает, если сложение связано с переносом, поскольку перенос распространяется справа налево. Замена цифр не означает перенос направления переключателей, поэтому любые байты, переполняющие следующий байт, будут другими.

Давайте посмотрим на пример в шестнадцатеричном формате, делая вид, что порядковый номер означает, что каждый 4-битный клев поменяется местами:

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

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

8 16 + B 16 составляет 13 16 . Это 1 несут и добавляет к 6 в первой сумме. Но во второй сумме она не переносится вправо и добавляется к 6, она переносится влево и перетекает в третью шестнадцатеричную цифру.

0 голосов
/ 30 апреля 2019

Во-первых, следует отметить, что ваше предположение, что int в C имеет 16 битов, неверно.В большинстве современных систем int является 32-битным типом, поэтому, если мы поменяем (а не перевернем, который принимает дополнение), байты 5, мы получим 83886080, а не 1280

Хорошо, как уже говорили другие, ntohl(htonl(5) + htonl(6)) оказывается таким же , что и 5 + 6, только потому, что у вас есть небольшие числа, сумма их обращений не переполняется.Выбрав большее число, вы сразу увидите разницу


Однако это свойство действительно сохраняется в дополнении единицы для систем, в которых значения хранятся в 2меньшие части, как в этом случае

В дополнение к ним каждый выполняет арифметику с переносом конца , распространяя перенос обратно к переносу. Это делает арифметику дополнения endianнезависимый , если имеется только один внутренний «разрыв переноса» (т. е. сохраненное значение разбивается на два отдельных блока) из-за «циклического переноса»

Предположим, у нас есть xxyy и zztt, тогда xxyy + zzttсделано так:

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

Когда мы переворачиваем чанки, yyxx + ttzz переносится так же.Поскольку xx, yy, zz, tt - это куски битов любой длины, это работает для смешанного порядкового номера PDP или когда вы сохраняете 32-разрядное число в двух 16-разрядных частях, 64-разрядное число в двух 32-разрядных частях...

Например:

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

Или приведенный выше пример Джона Кугельмана: 0x68 + 0x0B = 0x73;0x86 + 0xB0 = 0x136 → 0x36 + 1 = 0x37

Конечный перенос является одной из причин, по которой их дополнение было выбрано для контрольной суммы TCP, поскольку вы можете легко вычислить сумму с более высокой точностью.16-разрядные ЦП могут работать в 16-разрядных блоках, как обычно, но 32- и 64-разрядные ЦП могут добавлять 32- и 64-разрядные блоки параллельно, не беспокоясь о переносе, когда SIMD недоступна, как метод SWAR

0 голосов
/ 30 апреля 2019

Кажется, это работает только потому, что вы случайно выбрали числа, которые достаточно малы, чтобы они, а также их сумма помещались в один байт. Пока все, что происходит в вашем номере, остается в пределах соответствующего байта, вы, очевидно, можете перетасовывать и перетасовывать свои байты, как хотите, это не будет иметь значения. Если вы выберете большее число, например, 1234 и 4321, вы заметите, что оно больше не будет работать. Фактически, вы, скорее всего, в конечном итоге будете вызывать неопределенное поведение, потому что ваш int переполнится & hellip;

Помимо всего этого, вы почти наверняка захотите прочитать это: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html

...