Aláíratlan számtani java

Mint tudja, a Java nincs előjel nélküli típus. Ha lehetne levelet C unsigned int (char. Long), a Java nem fog működni. Azonban gyakran van szükség aritmetikai műveletek számok előjel nélküli. Első pillantásra úgy tűnik, hogy előjel nélküli típus, elvileg, és ez nem különösebben szükség (gondolom, a MaxInt aláírt szám kevesebb, mint két alkalommal, szükség esetén a szám több, én csak sokáig, majd BigInteger). De a fő különbség nem igazán, hogy sok különböző nem-negatív számok tudunk egy aláírt vagy unsigned int, és hogyan rájuk aritmetikai műveletek végrehajtását és összehasonlítások. Ha a munka a bináris protokoll vagy bináris aritmetikai ahol fontos minden bit használt, képesnek kell lennie arra, hogy végre minden alapvető műveleteket aláíratlan módban. Tekintsük az alábbi lépéseket annak érdekében, hogy:

Konverzió byte rövid (int, hosszú)


A típuskényszerítéssel (int) SajatByte végre bővítése 32 bit a jele - ez azt jelenti, hogy ha a MSB bájt van állítva 1, az eredmény ugyanaz, mint a negatív szám, de írt 32 bites formátumban:

0xff -> 0xFFFFFFFF (-1)

Gyakran ez nem az, amit akartunk. Annak érdekében, hogy végre bővítése 32 bit előjel nélkül, és kap 0x000000ff. Java felírható:

Összehasonlítás kivéve mark


Az előjel nélküli összehasonlítások tömör képlet:


Bájt, rövid és hosszú, illetve állandók lesznek 0x80. 0x8000 és 0x8000000000000000L.

Összeadás, kivonás és szorzás


És itt van egy kellemes meglepetés - ezeket a műveleteket helyesen minden esetben. De kifejezést gondosan ellenőrizni kell annak biztosítása érdekében, hogy a műveleteket végeztek a számok az azonos típusú, mint bármely implicit konverziót végezni a terjeszkedés a jelet, és eredményre vezethetnek eltérő várható. Intrika hibák hibás parancsfájl végrehajtható nagyon ritkán.


Az üzletág a -256 256 ad nekünk 1. És szeretnénk 0xffffff00 / 0x100 adta 0x00ffffff. helyett 0xFFFFFFFF (-1). Bájt. rövid int és a döntés lesz az átmenet a szám nagyobb kapacitás:


De mi köze hosszú. Áthelyezés BigInteger ilyen esetekben általában nincs lehetőség - túl lassú. Továbbra is csak az, hogy mindent a saját kezébe, és végrehajtja a szétválás kézzel. Szerencsére minden ellopták előttünk - a Google Guava a megvalósítása előjel nélküli osztás sokáig. és elég fürge. Ha nem használja a könyvtárat, a legegyszerűbb módja, hogy szakadjon egy kódrészletet közvetlenül UnsignedLongs.java file:


A fordításhoz a kódot, szintén kölcsön végrehajtás összehasonlítani (nagyon hosszú):


és Longs.compare (hosszú, hosszú) + lepattintható (hosszú):

bitenkénti műszakban


Ahhoz, hogy teljesen befedje a téma kicsit műveletek, visszahívás is a műszakban. Az x86 assembly van egy csomó különböző csoportok, amelyek a Biteltolás - SHL, SHR, SAL, SAR, ROR, ROL, RCR, RCL. Az utolsó 4 ciklikusan műszakban, ezek megfelelői Java nem. De a logikai és aritmetikai műszakban vannak jelen. Logikai shift (nem veszi figyelembe a jel) - SHL (váltás balra) és SHR (eltolás jobbra) - hajtják végre Java és szolgáltatók gt; gt; gt; volt. A logikai műszakban gyorsan végezhet integer szorzás és osztás a hatalom két számot. Aritmetikai (jele véve) jobbra - SAR - hajtja végre az üzemeltető gt; gt;. Aritmetikai balratolást egyenértékű a logikai, és ezért nincs külön kezelő érte. Furcsának tűnhet, hogy az összeállítás egy különleges műveleti kód erre a műveletre, de valójában ez nem ugyanaz a dolog, hogy van, SAL ismétli SHL viselkedést, és azt mondja, jobb dokumentációt az Intel:

A váltás számtani bal (SAL) és shift logikai bal (SHL) utasítások ugyanazt a műveletet; úgy tolja a biteket céloperandus balra (felé több helyi értékű bit helyen). Minden egyes léptetési szám, a legnagyobb helyi értékű bit a cél operandus tolódik be a CF zászlót, és a legkisebb helyértékű bit nem törlődik (lásd ábra 7-7 a Intel®64 és IA-32 architektúrák Software Developer'sManual, 1. kötet ).

SAL, hogy adunk hozzá csak a szimmetria, tekintettel arra, hogy van egy jobbratolódást szétválasztása logikai és számtani. De Gosling úgy döntött, hogy nem zavarja (és azt hiszem, ez így van rendjén).

Tehát, mi a következő:

egy gt; 1; // jobbra tolódtak, figyelembe véve a jel (megegyezik a szétválás 2) gt; gt; gt; 1; // jobbra tolódtak, tekintet nélkül aláírja (aláíratlan egyenértékű osztás 2) 

Záró ajánlások


  • Ha az aritmetikai műveletek vezethet túlcsordulás a kiválasztott bit rács, akkor mindig pontosan jelzik, milyen tartományban megengedett értéke a változók lehetnek, és nyomon követni ezeket invariáns, forgalomba állításával (állítások). Például nyilvánvaló, hogy a szorzás két tetszőleges 32 bites előjel nélküli eredmény nem fér bele a 32 bit, és ha kell, hogy elkerüljük túlcsordulás, akkor vagy győződjön meg arról, hogy ez a hely soha nem lesz olyan helyzet, amelyben a termék nem fér bele a 32 bit vagy először át kell alakítania mindkét operandus hosszú (teljesítő a - 0xffffffffL). Itt, az úton, így könnyű hibázni, csak átalakítani egyik operandus. Nem kell átalakítani, hogy egy hosszú, egyrészt azért, mert ha a második operandus negatív, akkor átalakítható burkoltan hosszabbító jelet, és az eredményt megszorozzuk helytelen lesz.
  • Nagyvonalúan rendezni a zárójeles kifejezéseket használó bitenkénti műveletek. Az a tény, hogy a prioritás a bitműveletek Java meglehetősen furcsa és gyakran úgy viselkedik, nem nyilvánvaló módon. Sokkal jobb, hogy adjunk hozzá egy pár zárójelben, mint néhány órával keresni finom hibákat.
  • Ha szüksége van bármilyen típusú konstans hosszú, ne felejtsük el, hogy adjunk egy utótag L a végén a konstansok. Ha nem, akkor nem hosszú, és int, és közvetett módon a csökkentés hosszú Ismét lesz kellemetlen számunkra a jele kiterjesztése.

Tény, hogy egy ilyen kis ködösítés: helyes Integer.compare (a - 0x80000000, b - 0x80000000);. ahol, mivel egyértelmű, hogy hogyan működik. Haladunk a számokat 0-tól 0xffffffff hogy chaslam kezdve 0x80000000 hogy 0x7ffffff lineáris elmozdulás (kezdjük előjel nélküli számok, és az eredmény előjel nélküli, de a „amennyire lehetséges”, mert aritmetikai „kiegészítéseként a két „az összeadás és kivonás az azonos és az előjel nélküli és aláírt számok) - és akkor minden rendben, akkor lehet, hogy összehasonlításokat.

Hasonló trükkök gyakran, hogy együttműködik SSE.

Nos, akkor látni fogja, hogy 0x80000000 - ez egy különleges szám, hogy ő levonására, hogy adjunk, hogy mintegy XOR'it - még. Nem tudom, tényleg, mi értelme ebben ködösítés.

Hány éves vagy, akkor? Bitenkénti műveletek gyorsabb számítógépek '70 -es évek (és még akkor nem az összes)! Már a 80-as években hozzáadásával végeztük ugyanolyan sebességgel, mint a bit műveleteket!

Ha én jött fel öt másodpercen belül, akkor nyilvánvaló, hogy öt másodpercig. És másodszor, az összes ilyen mágikus dokumentálni kell. Itt még a függvény neve látható, hogy igen.
Ez nem más, mint zavaros Integer.compare (a ^ 0x80000000, b ^ 0x80000000), és minden bizonnyal sokkal markánsabban, mint a kódrészletet az öt funkció, amely egy cikket. Gondosan nézd, amit a cikk azt sugallja, hogy használja? Négy eljárások, melyek közül kettő nem egészen világos. És optimalizálása összehasonlítani ...

Igen igazad van matematikus, igen. 9 osszuk el 3 és kap egy 4 ... Nos, ez csak egy ünnep valamilyen!

Ui Csak ne adjon újabb „még nyilvánvalóbb” opciót. Végül eléred ugyanazt valami hasonló Guglovomu opciót. A 10. kísérlet. Én hiszek benned. De a kérdésre, hogy „miért a idióták minden nem annyira nyilvánvaló, hogy nekem”, mint már eltűnt. Vagy nem?

Azt is hozzá a legelső ajánlás: Soha ne használjon sehol, de óvatosan lokalizált modulok kölcsönhatásba örökölt adatok és az alacsony szintű protokollokat.
A könyvtár javolution Structural osztály dolgozik ilyen típusú adatok.

Néhány kivételes esetben, egy ilyen módszer, ez lehetséges, és hasznos lenne, de inkább egy Java szimbolikus típusú elegendő az adatok tárolásának szó hosszúságú, mint a város, mint egy wrapper. Egyszerűen azért, mert a folyamat kialakulásának e táncok lesz elfelejteni, és nem lesz a csodák, ha összehasonlítjuk aláírt előjel nélküli, „szabálytalan” tranzakciók stb

A jelzett idő az időzóna, amely fel van szerelve a készülék.