.\" Copyright 2024 Andrew V.Kosteltsev (kx@radix-linux.su)
.\"
.\"
.TH shifts 3 "December 27, 2024" "libmpu" "LibMPU Programmer's Manual"
.SH NAME
\fBishl\fP, \fBishr\fP, \fBisal\fP, \fBisar\fP \- операции сдвига на один бит
.SH SYNOPSIS
.nf
.B #include <libmpu.h>
.PP
.BI "void ishl( mpu_int *" c ", mpu_int *" a ", int " nb " );
.BI "void ishr( mpu_int *" c ", mpu_int *" a ", int " nb " );
.BI "void isal( mpu_int *" c ", mpu_int *" a ", int " nb " );
.BI "void isar( mpu_int *" c ", mpu_int *" a ", int " nb " );
.fi
.SH DESCRIPTION
Для операций сдвигов на один бит входным операндом служит переменная размером \fBnb\fP байт,
находящаяся по адресу \fBa\fP, результат помещается в переменную того же размера,
расположенную по адресу \fBc\fP. Пространства, занимаемые входной и выходной переменной
в памяти могут пересекаться, как частично, так и полностью, что не влияет на правильность
получаемого результата. Содержимое переменной, расположенной по адресу \fBa\fP останется
неизменным, после выполнения операции, если занимаемое ею пространство не пересекается
с пространством, занимаемым переменной \fBc\fP.
.PP
При выполнениии операций сдвига, флаг переноса \fBC\fP всегда содержит значение последнего
выдвинутого бита. Существуют следующие виды операций сдвига:
.PP
.RS 3
SHL \- логический беззнаковый сдвиг влево на один бит.
.RE
.RS 3
SHR \- логический беззнаковый сдвиг вправо на один бит.
.RE
.RS 3
SAL \- арифметический сдвиг влево на один бит.
.RE
.RS 3
SAR \- арифметический сдвиг вправо на один бит.
.RE
.PP
Следующие таблицы иллюстрируют выполнение операций \fBishl\fP, \fBishr\fP.
.nf
.sp
┌────────────────┬───┬───────────────────┬────────────┐
│ SHL(<<): │ C │ значение операнда │ заполнение │
├────────────────┼───┼───────────────────┼────────────┤
│ до операции │ │ 10110111 │ 0 │
├────────────────┼───┼───────────────────┼────────────┤
│ после операции │ 1 │ 01101110 │ │
└────────────────┴───┴───────────────────┴────────────┘
┌────────────────┬────────────┬───────────────────┬───┐
│ SHR(>>): │ заполнение │ значение операнда │ C │
├────────────────┼────────────┼───────────────────┼───┤
│ до операции │ 0 │ 10110111 │ │
├────────────────┼────────────┼───────────────────┼───┤
│ после операции │ │ 01011011 │ 1 │
└────────────────┴────────────┴───────────────────┴───┘
.fi
.sp
Из таблиц видно, что при любом логическом сдвиге на освободившееся место всегда задвигается 0.
Флаг переполнения \fBO\fP выставляется, если в результате операции операнд изменил знак.
.PP
Операция арифметического сдвига влево \fBisal\fP действует аналогично операции \fBishl\fP
(также на пустое место справа задвигается 0). Операция арифметического сдвига вправо действует
иначе: в освобождающуюся позицию слева копируется знаковый бит исходного операнда.
Действие операций \fBisal\fP и \fBisar\fP показано с помощью следующих таблиц.
.nf
.sp
┌────────────────┬───┬───────────────────┬────────────┐
│ SAL(<<): │ C │ значение операнда │ заполнение │
├────────────────┼───┼───────────────────┼────────────┤
│ до операции │ │ 10110111 │ 0 │
├────────────────┼───┼───────────────────┼────────────┤
│ после операции │ 1 │ 01101110 │ │
└────────────────┴───┴───────────────────┴────────────┘
┌────────────────┬────────────┬───────────────────┬───┐
│ SAR(>>): │ заполнение │ значение операнда │ C │
├────────────────┼────────────┼───────────────────┼───┤
│ до операции │ sign(1) │ 10110111 │ │
├────────────────┼────────────┼───────────────────┼───┤
│ после операции │ │ 11011011 │ 1 │
└────────────────┴────────────┴───────────────────┴───┘
.fi
.sp
Флаг переполнения при выполнении операции \fBisal\fP выставляется таким же образом, как
и при операции \fBishl\fP. При выполнении операции \fBisar\fP, операнд не может изменить
свой знак. Многократный сдвиг \fBisar\fP может, в конце концов, привести к потере значения,
и положительное число задвинется в 0, а отрицательное в -1. По этому флаг переполнения \fBO\fP
для операции \fBisar\fP сбрасывается в 0.
.PP
При выполнении операций \fBisal\fP, \fBisar\fP, \fBishl\fP, \fBishr\fP, так же выставляются
флаги четности \fBP\fP, знака \fBS\fP и нуля \fBZ\fP. Флаг переноса из младшей тетрады \fBA\fP
не определяется и просто сбрасывается в 0.
.PP
Сдвиг влево можно применять для удваивания чисел, а сдвиг вправо \- для деления на 2. Эти операции
выполняются значительно быстрее, чем операции умножения и деления. Деление пополам нечетных чисел
(например, 5 или 7) образует меньшие значения (2 или 3, соответственно) и устанавливает флаг
переноса \fBC\fP в 1. При этом \fBC\fP, фактически, содержит остаток от деления. Такое использование
операций сдвига требует контроля за флагом переполнения \fBO\fP. Для простоты, рассмотрим контроль
флагов на 4\-битных знаковых переменных:
.SS Примеры с 4\-битными операндами:
\fBУмножение на 2\fP:
.nf
SAL(0111) = 7; результат = 1110 = -2, ошибка, должно быть 14, CF = 0, OF = 1
.fi
.sp
\fBДеление на 2\fP:
.nf
SHR(1000) = -8; результат = 0100 = 4, ошибка, должно быть -4, CF = 0, OF = 1
.fi
.sp
\fBДеление на 2\fP:
.nf
SAR(1000) = -8; результат = 1100 = -4, абсолютно точно, CF = 0, OF = 0
.fi
.sp
\fBДеление на 2\fP:
.nf
SAR(0111) = 7; результат = 0011 = 3, остаток 1 (см. флаг C), абсолютно точно, CF = 1, OF = 0
.fi
.sp
.SH EXAMPLES
.nf
.sp
#include <libmpu.h>
#include <stdio.h>
int main( void )
{
int rc = 0;
__mpu_init();
__mpu_extra_warnings = 1;
{
mpu_int8_t c, a;
int nb = NB_I8;
__mpu_char8_t sc[32], sa[32];
iatoi( a, "0b10110111", nb ); /* evaluate the A variable */
ishl( c, a, nb );
iitoa( sa, a, RADIX_BIN, LOWERCASE, nb ); /* convert A value to ASCII string SA */
iitoa( sc, c, RADIX_BIN, LOWERCASE, nb ); /* convert C value to ASCII string SC */
printf( "a = %s;\\n", sa ); /* c = 0b10110111; */
printf( "c = %s;\\n", sc ); /* c = 0b01101110; */
printf( "carry = %d;\\n", __mpu_gtc() ); /* Carry Flag */
printf( "overflow = %d;\\n", __mpu_gto() ); /* Overflow Flag */
}
__mpu_free_context();
return( rc );
}
.fi
.SH SEE ALSO
.BR iadd(3),
.BR isub(3),
.BR iadc(3),
.BR isbb(3),
.BR irol(3),
.BR iror(3),
.BR ircl(3),
.BR ircr(3),
.BR ishln(3),
.BR ishrn(3),
.BR isaln(3),
.BR isarn(3),
.BR iroln(3),
.BR irorn(3),
.BR ircln(3),
.BR ircrn(3),
.BR ineg(3),
.BR inot(3),
.BR iand(3),
.BR itest(3),
.BR icmp(3),
.BR ior(3),
.BR ixor(3),
.BR iinc(3),
.BR idec(3),
.BR ixchg(3),
.BR icpy(3),
.BR icvt(3),
.BR imul(3),
.BR ismul(3),
.BR idiv(3),
.BR isdiv(3),
.BR iatoi(3),
.BR iatoui(3),
.BR iitoa(3),
.BR iuitoa(3).