ПредишенСледващото

Както знаете, Java още няма неподписани типове. Ако можете да напишете C неподписан инт (Чар. Long), в Java това няма да стане. Въпреки това, често е необходимо да се извършват аритметични операции с числа е неподписан. На пръв поглед изглежда, че неподписани типове, по принцип, и това не е особено необходимо (мисля, за MaxInt подписан номера по-малко от два пъти, ако е необходимо броят на повече, просто ще отнеме много време, а след това BigInteger). Но основната разлика не е наистина, че много различни не-отрицателни числа могат да бъдат поставени в подписа или неподписани вътр и как на тях да изпълнява аритметични операции и сравнения. Ако работите с двоичен протокол или двоична аритметика, където важно всеки бит се използва, трябва да е в състояние да изпълнява всички основни операции в неподписан режим. Помислете за тези стъпки, за да:

байт реализациите в краткосрочен (инт, дълго)


Обичайната актьорския състав (инт) myByte извърши разширение до 32 бита със знак - това означава, че ако MSB на байт е настроен на 1, резултатът е същият като отрицателно число, но написано в 32-битов формат:

0xff -> 0xFFFFFFFF (-1)

Често това не е това, което искахме. За да се извърши разширение до 32 бита, без знак и получавате 0x000000ff. в Java може да се запише:

Сравнете с изключение на марка


За неподписани сравнения имат кратък формула:


За байт, къси и дълги, съответно, ще бъдат константи 0x80. 0x8000 и 0x8000000000000000L.

Събиране, изваждане и умножение


И тук е приятна изненада - тези операции се извършват правилно във всеки случай. Но изрази трябва да се наблюдават внимателно, за да се гарантира, че операциите са извършени с цифрите от същия тип, като всички неявни преобразувания се извършват с разширяването на марката, и може да доведе до резултати, различни от очакваните. Интрига на грешки, които погрешно скрипт може да се изпълнява много рядко.


Разделението на -256 до 256 ще ни даде 1. И ние бихме искали да 0xffffff00 / 0x100 даде 0x00ffffff. вместо 0xFFFFFFFF (-1). За байт. Накратко вътр и решението ще бъде преход към броя на по-голям капацитет:


Но какво да се прави с дълго. Преместване в BigInteger в такива случаи обикновено не е опция - твърде бавно. Остава само да се вземе всичко в свои ръце и прилагане на разделението на ръка. За щастие, всичко е било откраднато преди нас - в Google Гуава е реализацията на неподписан подразделение за дълго. и доста пъргав. Ако не използвате библиотеката, най-лесният начин да се откъсне част от код директно от UnsignedLongs.java файл:


За да компилирате кода, също заемат изпълнение сравнение (много дълго):


и Longs.compare (дълго, дълго) + флип (дълго):

побитови смени


За да се покрият напълно темата за битови операции, припомним също и на смени. В x86 асемблер има цял куп различни екипи, които правят смяна малко - SHL, SHR, SAL, SAR, ROR, ROL, RCR, RCL. Последните 4 изпълнява циклични промени, техните еквиваленти в Java не. Но логически и аритметични измества са налице. Логическо изместване (не се вземат предвид знака) - SHL (измести вляво) и СБР (измести вдясно) - се осъществява в Java и оператори GT; GT; GT; съответно. С логични промени могат бързо да изпълнявате число умножение и деление с мощност от два броя. Аритметика отместване (влезте в профила) надясно - ДАБ - се осъществява от оператора GT; GT;. Аритметика олевяване е еквивалентно на логически, и следователно няма специални оператор за него. Може да изглежда странно, че събранието е специален код на операция за тази операция, но в действителност той прави същото нещо, което е, SAL повтаря поведение SHL, и то се казва дясната документация от Intel:

смяна аритметика Левият (SAL) и измести логично ляв (ШЛ) инструкции изпълняват една и съща операция; те измести битовете в операнда дестинация на ляво (към по-значими места битови). За всеки брой смени, най-важният бит на операнда дестинация е изместен в флаг CF, и най-маловажният бит се изчиства (виж фигура 7-7 в Intel®64 и IA-32 архитектури Софтуер Developer'sManual, том 1 ).

SAL, която се добавя само за симетрия, като се има предвид факта, че е налице промяна на правилното разделяне на логика и аритметика. Но Гослинг не реши да се притеснява (и мисля, че с право).

Така че, ние имаме следното:

а GT; 1; // измести надясно, като се вземат предвид знака (еквивалент на разделение от 2) GT; GT; GT; 1; // измести надясно, без оглед да подпише (неподписана, еквивалентен на разделение на 2) 

Заключителни препоръки


  • При извършване на аритметични операции, които могат да доведат до препълване на избраната битова мрежа, винаги трябва да го представя точно това, което може да бъде от порядъка на допустимите стойности за променливите, и да следите за тези инварианти, пускане твърдения (твърдения). Например, очевидно е, че размножаването на две произволни 32-битова неподписан резултат не може да се побере в 32 бита, и ако е необходимо да се избегне преливане, трябва или да се уверите, че това място никога няма да бъде ситуация, в която продуктът не се вписва в 32 бита или първо трябва да конвертирате и двата операнда в дългосрочен (извършване а - 0xffffffffL). Тук, между другото, е лесно да се направи грешка, само да я превърне в един от най-операнди. Няма нужда да се превърне в един дълъг, както поради ако на втория операнд е отрицателно, тя ще бъде превърната имплицитно дълго удължаване марка, и умножаване на резултата може да е неправилно.
  • Щедро организира скобите в изрази, които използват побитови операции. Фактът, че приоритетът на побитови оператори в Java доста странно и често се държи в не-очевиден начин. По-добре е да се добавят няколко скоби, отколкото до няколко часа, за да търсят се допусне грешка.
  • Ако имате нужда от всякакъв вид постоянна дълго, не забравяйте да добавите наставка L В края на буквалните константи. Ако не го направите, няма да дълго, и инт, и косвено до намаляване дълго Отново ще има неприятна за нас с разширение знак.

В действителност, тя е такава малка еквилибристика: правилно да Integer.compare (а - 0x80000000, б - 0x80000000). където, тъй като е ясно как работи. Ние се премести от числа между 0 до 0xffffffff да chaslam вариращи от 0x80000000 да 0x7ffffff чрез линейна смяна (ние започваме с неподписани числа, а резултатът не е подписана, но "това е възможно", тъй като в аритметика ", като допълнение на две "събиране и изваждане на едни и същи и за неподписани и подписани номера) - и след това всичко е наред, може да се правят сравнения.

Подобни трикове често трябва да направи работата с SSE.

Е, тогава вие ще забележите, че 0x80000000 - това е специален номер, който той удържа, че това добави, че около XOR'it - все още. Не знам, наистина, какъв е смисълът в това объркване.

На колко години сте, а след това? Побитови операции са 70-те по-бързи компютри "(и дори тогава не всички)! Още през 80-те добавянето се извършва със същата скорост като операциите по битови!

Ако бях дошъл с пет секунди, очевидно е, че в продължение на пет секунди. И второ, всички като магия трябва да бъдат документирани. Тук дори името на функцията може да се види, че го прави.
Това не е нищо повече от объркващо Integer.compare (а ^ 0x80000000, б ^ 0x80000000) и със сигурност много по-ясно от това, част от кода на петте функции, което е една статия. Трябва внимателно да изглежда това, което статията предполага да се използва? Четири процедури, две от които не са съвсем ясни. И оптимизация за сравнение ...

Да прав сте математик, да. 9 разделете на 3 и да получите 4. ... Ами това е само празник на някакъв вид!

Послепис Само не даде друг "още по-очевидна" опция. В крайна сметка да постигнете същото и на нещо като Guglovomu опция. На 10-ия опит. Аз вярвам в теб. Но на въпроса "защо всички идиоти, не всичко е толкова очевидно за мен", като има вече изчезнали. Или не?

Искам да добавя, най-първата препоръка: Никога не използвайте навсякъде, но внимателно локализиран модули взаимодействат с стари данни и протоколи от ниско ниво.
Библиотеката разполага javolution Struct клас за работа с този тип данни.

За някои изключителни случаи, като метод, е възможно и би било от полза, но предпочитам използването на Java символични видове достатъчно за съхранение на дължината на думата данни от града като обвивка. Просто защото в процеса на разработване на тези танци, ще бъдат забравени, и няма да има чудеса, когато се сравнява подписа с неподписани "нередовните" сделки, и т.н.

Времето, посочено в часовата зона, която е монтирана в устройството.

Подкрепете проекта - споделете линка, благодаря!