Рассмотрим, как вы добавляете два двузначных числа, используя однозначную арифметику.
42
+39
---
Сначала вы добавите правый столбец. («Единицы» или «единицы»). 2 + 9 равно 11. 11 «переполнило» вашу 1-значную арифметику, поэтому вы должны «нести» 10.
1
42
+39
---
1
Теперь вы сложите левый столбец "десятки", включая перенос. 1 + 4 + 3 = 8.
1
42
+39
---
81
8 меньше 10, так что не переносите. Вы сделали.
Что только что произошло? Когда вы говорите, что число «42» (в базе 10), вы действительно имеете в виду
4*10+2
Или, что эквивалентно,
4*10^1+2*10^0
(когда я говорю «a ^ b», например, «10 ^ 1», я имею в виду «a, возведенное в b'th степень»: умножается на b раз. 10 ^ 0 равно 1. 10 ^ 1 равно 10. 10 ^ 2 - это 10 * 10 = 100 ...)
Когда вы добавляете «42» и «39», вы говорите
4*10+2+3*10+9
Что равно
(4+3)*10+(2+9)*1
(4+3)*10+(11)*1
(4+3)*10+(1*10+1)*1
Теперь, поскольку «11» не является действительным однозначным числом, вам нужно вынести 10 из них, превратив его в 1 в десятке.
(4+3)*10+(1)*10+(1)*1
(4+3+1)*10+(1)*1
(8)*10+(1)*1
, что составляет 81.
Итак, почему я говорил об этом, а не о вашем вопросе о 64-разрядных числах и 32-разрядной арифметике? Потому что они на самом деле точно такие же!
Цифра находится в диапазоне от 0 до 9. «32-битное число» находится в диапазоне от 0 до 2 ^ 32-1. (Предполагая, что это без знака.)
Итак, вместо того, чтобы работать в базе 10, давайте работать в базе 2 ^ 32. В базе 2 ^ 32 мы записываем 2 ^ 32 как 10. Если вы пишете 64-битное число в базе 2 ^ 32, это будет
(x)*10+y
где x и y - символы для чисел от 0 до 2 ^ 32-1. Эти символы являются цепочками битов.
Если вы хотите добавить два 64-битных числа, разбейте их в базе 2 ^ 32 следующим образом:
a_1*10+a_0
+b_1*10+b_0
Теперь вы добавляете их в базу 2 ^ 32 точно так же, как вы добавляете их в базу 10 - просто вместо добавления с использованием арифметики с цифрами, добавляемой с помощью 32-битной арифметики!
Как разделить 64-битное число a на два 32-битных числа a_1 и a_0? Разделите на 2 ^ 32. Не с плавающей точкой, а целочисленно - где вы получаете дивиденд и остаток. Дивиденд равен a_1, остаток равен a_0.
К сожалению, для этого требуется 64-битная арифметика. Однако, как правило, a_1 является «самой значительной половиной» a, поэтому в синтаксисе стиля C:
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
где >> - правильное битовое смещение, а & - побитовое и.
Как правило, если вы не можете выполнить 64-битное сложение, «64-битное число» фактически будет двумя 32-битными числами a_1 и a_0. У вас не будет uint64_t, если вы не можете выполнять арифметику uint64_t!
Все это предполагает, что вы выполняете арифметику без знака, но отсюда легко разобраться со знаками.