Кіріспе

Компьютерлік бағдарламалаудағы ауысу операторы

+ Әр түрлі бағдарламалау тілдері мен процессорлардағы арифметикалық ауысу операторы
Тіл немесе процессор Солға Оңға
ActionScript 3, Java, JavaScript, Python, PHP, Ruby, C, C++, D, C#, Go, Julia, Rust (тек таңбалы типтер), Swift (тек таңбалы типтер) << >>
Ada Солға ауысу Оңға ауысу Арифметикалық
Kotlin shl shr
Fortran SHIFTL SHIFTA
Standard ML << ~>>
Verilog <<< >>>
OpenVMS макро тілі @
Scheme арифметикалық ауысу
Common Lisp ash
OCaml lsl asr
Haskell Data.Bits.shift
VHDL sla sra
Assembly: Z80 SLA SRA
Assembly: x86 SAL SAR
Assembly: 68k ASL ASR
Assembly: RISC V sll, slli sra, srai

Компьютерлік бағдарламалауда арифметикалық ауысу – бұл ауысу операторы, кейде таңбалы ауысу деп аталады (бірақ ол тек таңбалы операндармен шектелмейді). Екі негізгі түрі – арифметикалық солға және арифметикалық оңға ауысу. Бинарлық сандар үшін бұл операндының барлық биттерін жылжытатын биттік операция; операндағы әрбір бит белгілі бір санға қадамдармен жылжытылады, ал бос қадамдар толтырылады. Логикалық ауысудағыдай, барлық 0-мен толтырудың орнына, оңға ауысқанда, ең сол биті (әдетте, таңбалы бүтін сандарды бейнелеудегі таңба биті) барлық бос орындарды толтыру үшін көшіріледі (бұл таңбаны кеңейтудің бір түрі). Кейбір авторлар арифметикалық және логикалық ауысулар үшін сәйкесінше «жабысқақ оңға ауысу» және «нөлмен толтыру оңға ауысу» терминдерін қолдануды ұсынады. Арифметикалық ауысулар таңбалы бүтін сандарды екіге көбейту немесе бөлудің тиімді тәсілі болуы мүмкін. Таңбалы немесе таңбасыз бинарлық санды n битпен солға жылжыту оны 2n-ге көбейтуге тең. Екілік толықтыру түріндегі таңбалы бинарлық санды n битпен оңға жылжыту оны 2n-ге бөлуге тең, бірақ ол әрқашан төмен қарай дөңгелектейді (теріс шексіздікке қарай). Бұл таңбалы бүтін санды бөлудегі әдеттегі дөңгелектеуден өзгеше (ол 0-ге қарай дөңгелектеледі). Бұл қарама-қайшылық бірнеше компиляторларда қателерге әкелді. Мысалы, x86 нұсқаулар жиынтығында SAR (арифметикалық оңға ауысу) нұсқауы таңбалы санды екіге бөліп, теріс шексіздікке қарай дөңгелектейді. IDIV нұсқауы (таңбалы бөлу) таңбалы санды нөлге қарай дөңгелектеп бөледі. Сондықтан SAR нұсқауын IDIV нұсқауымен немесе керісінше, екінің дәрежесімен алмастыруға болмайды.

Арифметикалық және логикалық солға ауысулар мен көбейтудің теңдігі

Арифметикалық солға жылжытулар радикстің (оң, бүтін) дәрежесіне көбейтуге баламалы (мысалы, екілік сандар үшін 2-нің дәрежесіне көбейту). Логикалық солға жылжытулар да баламалы, бірақ көбейту және арифметикалық жылжытулар арифметикалық шамадан асып кетуге алып келуі мүмкін, ал логикалық жылжытулар олай емес.

Арифметикалық оңға ауысу мен бөлудің теңдестірілмеуі

Алайда, арифметикалық оңға жылжыту – салмақты ойламайтын адамдарға түсірілетін басты қауіп, әсіресе теріс бүтін сандарды дөңгелектеу кезінде. Мысалы, теріс бүтін сандардың әдеттегі екілік толықтырғыш түрінде -1 саны барлық 1-дерден тұрады. 8 биттік бүтін сан үшін бұл 1111 1111 болады. Арифметикалық оңға 1 (немесе 2, 3, …, 7) бітпен жылжыту қайтадан 1111 1111 санын береді, яғни бұл әлі де -1. Бұл төменге қарай дөңгелектеуге (теріс шексіздікке қарай) сәйкес келеді, бірақ бұл әдетте бөлу үшін қолданылмайды. Көптеген жағдайларда арифметикалық оңға жылжыту радикстің (оң, бүтін) дәрежесіне бөлуге тең деп айтылады (мысалы, екілік сандар үшін 2-нің дәрежесіне бөлу), сондықтан радикстің дәрежесіне бөлуді арифметикалық оңға жылжыту арқылы жүзеге асыру арқылы оңтайландыруға болады. (Жылжытқыш бөлгіштен әлдеқайда қарапайым. Көптеген процессорларда жылжыту командалары бөлу командаларынан жылдам орындалады.) 1960 және 1970 жылдардағы көптеген бағдарламалау оқулықтары, нұсқаулықтары және DEC, IBM, Data General және ANSI сияқты компаниялар мен ұйымдардың басқа да сипаттамалары мұндай дұрыс емес мәлімдемелер жасайды. Логикалық оңға жылжыту тек оң немесе белгісіз сандар үшін радикстің (әдетте 2) дәрежесіне бөлуге тең. Арифметикалық оңға жылжыту оң таңбалы сандар үшін логикалық оңға жылжытуға тең. N-нің толықтырғыш түрінде (әдетте екілік толықтырғыш) теріс сандар үшін арифметикалық оңға жылжыту радикстің (әдетте 2) дәрежесіне бөлуге шамамен тең, онда тақ сандар үшін төменге қарай дөңгелектеу қолданылады (әдетте күтілетіндей 0-ге қарай емес). Теріс сандар үшін арифметикалық оңға жылжыту, кейбір тарихи компьютерлерде қолданылғандай, қол қойылған сандардың бірлік толықтырғыш түрінде 0-ге қарай дөңгелектеуді пайдалана отырып бөлуге тең, бірақ бұл қазіргі уақытта кеңінен қолданылмайды.

Мәселені бағдарламалау тілдерінде шешу

C бағдарламалау тілі үшін 1999 жылғы ISO стандарты оңға жылжыту операторын 2-нің дәрежесіне бөлу арқылы анықтайды. Жоғарыда айтылғандай, эквиваленттілік болмағандықтан, стандартта теріс мәні бар саналған сандардың оңға жылжытылуы осы анықтамадан нақты түрде алынып тасталады. Ол мұндай жағдайларда оңға жылжыту операторының қалай жұмыс істейтінін нақты көрсетпейді, бірақ әрбір C компиляторы теріс мәндерді оңға жылжытудың қалай жұмыс істейтінін анықтауын талап етеді. C сияқты, C++-та C++20-ға дейін саналған бүтін сандар үшін оңға жылжыту компилятормен анықталатын. C++20 стандартынан бастап, саналған бүтін санның оңға жылжытылуы арифметикалық жылжыту деп анықталады.

Қолданбалар

Тұрақты төменгі дөңгелектеу қажет болған жағдайларда, қол қойылған мәндер үшін арифметикалық оңға жылжу пайдалы. Мысалы, растрлық координаттарды екінің дәрежесімен кішірейту, бұл тең арақашықтықты сақтайды. Мысалы, 1-ге оңға жылжу 0, 1, 2, 3, 4, 5 сандарын 0, 0, 1, 1, 2, 2-ге, ал −1, −2, −3, −4 сандарын −1, −1, −2, −2-ге түрлендіреді, бұл −2, −2, −1, −1, 0, 0, 1, 1, 2, 2 тең арақашықтығын сақтайды. Керісінше, нөлге қарай дөңгелектеумен бүтін санға бөлу −1, 0 және 1 сандарын барлығын 0-ге жібереді (2 орнына 3 нүкте), нәтижесінде −2, −1, −1, 0, 0, 0, 1, 1, 2, 2 болады, бұл 0-де бұрмаланған.