В T-SQL (SQL Server MS), это работает:
SELECT
CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END FieldContent,
COUNT(*) FieldCount
FROM
TheTable
GROUP BY
CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END
Сначала добавьте младшие байты, сохраните перенос. Добавьте наиболее значимые байты с учетом переноса из LSB:
; x86 assembly, Intel syntax
; adds ecx:ebx to edx:eax
add eax, ebx
adc edx, ecx
Ранее опубликованный код C излишне подробен:
unsigned a1, b1, a2, b2, c1, c2;
c1 = a1 + b1;
c2 = a2 + b2;
if (c1 < a1)
c2++;
'a1' в 'if' также можно заменить на 'b1'. При переполнении c1 будет меньше, чем a1 и b1.
Если 64 -битовые числа: (a 2 , a 1 ) и (b 2 , b 1 ), где x 2 - это старшие 32 бита, принятые как беззнаковые, а x 1 - младшие 32 бита, взятые как беззнаковые, тогда сумма двух чисел приведена ниже.
c1 = a1 + b1
c2 = a2 + b2
if (c1 < a1 || c1 < b1)
c2 += 1
Подумайте, как вы складываете два двузначных числа, используя однозначную арифметику.
42
+39
---
Сначала вы добавляете правый столбец. («Единицы» или «единицы»). 2 + 9 равно 11. 11 "переполнило" вашу однозначную арифметику, поэтому вам нужно "перенести" 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», я имею в виду «повышенный в b-й степени ": a умножается на себя 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? Разделите a на 2 ^ 32. Не с плавающей запятой, а целочисленно - где вы получаете дивиденд и остаток. Делимое равно a_1, остаток - a_0.
К сожалению, для этого требуется 64-битная арифметика. Однако обычно a_1 - это «старшая половина», поэтому в синтаксисе стиля C:
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
где >> - это правый битовый сдвиг, а & - побитовое и.
Обычно, если вы не можете выполнить 64-битное сложение , «64-битное число» будет фактически двумя 32-битными числами a_1 и a_0. У вас не будет uint64_t, если вы не сможете выполнять арифметические операции с uint64_t!
Все это предполагает, что вы выполняете арифметические операции без знака, но работать со знаками здесь легко.
Как разделить 64-битное число a на два 32-битных числа a_1 и a_0? Разделите a на 2 ^ 32. Не с плавающей запятой, а целочисленно - где вы получаете дивиденд и остаток. Делимое равно a_1, остаток - a_0.
К сожалению, для этого требуется 64-битная арифметика. Однако обычно a_1 - это «старшая половина», поэтому в синтаксисе стиля C:
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
где >> - это правый битовый сдвиг, а & - побитовое и.
Обычно, если вы не можете выполнить 64-битное сложение , «64-битное число» будет фактически двумя 32-битными числами a_1 и a_0. У вас не будет uint64_t, если вы не сможете выполнять арифметические операции с uint64_t!
Все это предполагает, что вы выполняете арифметические операции без знака, но работать со знаками здесь легко.
Как разделить 64-битное число a на два 32-битных числа a_1 и a_0? Разделите a на 2 ^ 32. Не с плавающей запятой, а целочисленно - где вы получаете дивиденд и остаток. Делимое равно a_1, остаток - a_0.
К сожалению, для этого требуется 64-битная арифметика. Однако обычно a_1 - это «старшая половина», поэтому в синтаксисе стиля C:
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
где >> - это правый битовый сдвиг, а & - побитовое и.
Обычно, если вы не можете выполнить 64-битное сложение , «64-битное число» будет фактически двумя 32-битными числами a_1 и a_0. У вас не будет uint64_t, если вы не сможете выполнять арифметические операции с uint64_t!
Все это предполагает, что вы выполняете арифметические операции без знака, но работать со знаками здесь легко.
но целочисленно - где вы получаете дивиденд и остаток. Делимое равно a_1, остаток - a_0.К сожалению, для этого требуется 64-битная арифметика. Однако обычно a_1 - это «старшая половина», поэтому в синтаксисе стиля C:
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
где >> - это правый битовый сдвиг, а & - побитовое и.
Обычно, если вы не можете выполнить 64-битное сложение , «64-битное число» будет фактически двумя 32-битными числами a_1 и a_0. У вас не будет uint64_t, если вы не сможете выполнять арифметические операции с uint64_t!
Все это предполагает, что вы выполняете арифметические операции без знака, но работать со знаками здесь легко.
но целочисленно - где вы получаете дивиденд и остаток. Делимое равно a_1, остаток - a_0.К сожалению, для этого требуется 64-битная арифметика. Однако обычно a_1 - это «старшая половина», поэтому в синтаксисе стиля C:
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
где >> - это правый битовый сдвиг, а & - побитовое и.
Обычно, если вы не можете выполнить 64-битное сложение , «64-битное число» будет фактически двумя 32-битными числами a_1 и a_0. У вас не будет uint64_t, если вы не сможете выполнять арифметические операции с uint64_t!
Все это предполагает, что вы выполняете арифметические операции без знака, но работать со знаками здесь легко.
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
где >> - сдвиг вправо, а & - побитовое и.
Обычно, если вы не можете выполнить 64-битное сложение, «64-битное число» фактически будет двумя 32-битными числами a_1 и a_0. У вас не будет uint64_t, если вы не сможете выполнять арифметические операции с uint64_t!
Все это предполагает, что вы выполняете арифметические операции без знака, но работать со знаками здесь легко.
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
где >> - сдвиг вправо, а & - побитовое и.
Обычно, если вы не можете выполнить 64-битное сложение, «64-битное число» фактически будет двумя 32-битными числами a_1 и a_0. У вас не будет uint64_t, если вы не сможете выполнять арифметические операции с uint64_t!
Все это предполагает, что вы выполняете арифметические операции без знака, но работать со знаками здесь легко.
это выглядит примерно так
/* break up the 64bit number into smaller, 16bit chunks */
struct longint {
uint16 word0;
uint16 word1;
uint16 word2;
uint16 word3;
};
uint16 add(longint *result, longint *a, longint *b)
{
/* use an intermediate large enough to hold the result
of adding two 16 bit numbers together. */
uint32 partial;
/* add the chunks together, least significant bit first */
partial = a->word0 + b->word0;
/* extract thie low 16 bits of the sum and store it */
result->word0 = partial & 0x0000FFFF;
/* add the overflow to the next chunk of 16 */
partial = partial >> 16 + a->word1 + b->word1;
/* keep doing this for the remaining bits */
result->word1 = partial & 0x0000FFFF;
partial = partial >> 16 + a->word2 + b->word2;
result->word2 = partial & 0x0000FFFF;
partial = partial >> 16 + a->word3 + b->word3;
result->word3 = partial & 0x0000FFFF;
/* if the result overflowed, return nonzero */
return partial >> 16;
}
Фактическое оборудование не использует 32 бита для добавления 16 бит за раз, для добавления всегда требуется только один дополнительный бит переноса, и почти все ЦП имеют флаг состояния переноса на случай переполнения операции сложения, поэтому, если вы используете 32-битный ЦП, вы можете добавить 64-битные операнды за две 32-битные операции.
Практически каждый процессор имеет бит переноса и операцию добавления с переносом, о которых вы заботитесь только в том случае, если вы программируете на ассемблере. Если вы используете более высокий язык, компилятор выводит точно такие же операции добавления с переносом. Мой AVR-GCC дал мне это при добавлении двух 16-битных чисел - AVR - 8-битный - но те же принципы применимы и к более мощным процессорам.
Данные числа находятся в регистрах R1: R2 и R3: R4:
ADD R2,R4 ; first add the two low-bytes, result stored into R2
ADC R1,R3 ; then the two high-bytes and the carry bit, into R1
Результат сохраняется в R1: R2.