» »

[C++] Shift left

[C++] Shift left

«
1
2

Thomas ::

Tole mene bega.

Konkretno bolj tole:

The result of a shift operation is undefined if the second operand is negative, or if the right operand is greater than or equal to the width in bits of the promoted left operand.


Če recimo preveč šiftaš v levo, dobiš NEDEFINIRAN rezultat. Huh ...

A ma kdo kakšen komentar?

BigWhale ::

Se mi zdi, da govori zgolj o desnem shiftu... No saj oboje je podobno.

Ce prevec v levo shiftas ti prej ali slej zmanjka prostora za vrednost, odvisno od tipa spremenljivke pac. Ce byte desethrat shiftas v levo, bo stala. Ce ga pa shiftas za negativno vrednost bos pa prisel na nic.

Ce pa prevec shiftas v desno, bos pa prej ali slej prisel na 0.
Ce pa shiftas za negativno vrednost, te bo pa pricakal division by zero. Ker se ti bo tvoj shift prevec odshiftal, stevilka bo pa zaokrozena na nic...

In to je potem nepredviden rezultat. :)

Zgodovina sprememb…

  • spremenil: BigWhale ()

BigWhale ::

Sicer pa, a ni

1 << -2 = 1 >> 2

in

1 >> -2 = 1 << 2


?

Quikee ::

Ha ?
Ok s tem se sploh ne strinjam... ce mas BYTE oz. unsigned char pa preveckrat shiftas v levo ali desno dobis vrednost 0. Isto velja za signed char.

Quikee ::

Ni isto... ker v primeru recimo << -2 ne bi vzel za vrednost -2 ampak pomoje 254 .. ker operator >> pricakuje unsighned vrednost. Pomoje..

Thomas ::

> ce mas BYTE oz. unsigned char pa preveckrat shiftas v levo ali desno dobis vrednost 0. Isto velja za signed char.

To se jest strinjam. Samo pravijo, da stvari ne delajo tako. In tudi ne delajo, smo probal.

OwcA ::

Kako delajo stvari, ki so v standardu nedefinirane je stvar prevajalnika in zato tega ne gre splošiti.

Lahko pa povoziš (operator overloading) oba shift operatorja in ju prirediš svojim potrebam.
Otroška radovednost - gonilo napredka.

Zgodovina sprememb…

  • spremenilo: OwcA ()

Thomas ::

V assemblerju shift left N, M pomeni shift left N, (M mod 32).

C++ je pa baje kar nedefiniran ... morm se naučit s tem živet.

Zgodovina sprememb…

  • spremenil: Thomas ()

Quikee ::

"V assemblerju shift left N, M pomeni shift left N, (M mod 32)."
Kak to mislis ?
shift left N,M (shl N,M).. bo v assembleru register N shifto levo za M bitov. Samo pomoje je spet vprasanje kateri assembler mislis. =)

Thomas ::

Ne, ne. Opcode 0FA4 ali 0FA5, upošteva samo 5 spodnjih bitov. Za x86 arhitekturo, seveda.

Thomas ::

5 spodnjih bitov Mja, se razume.

Quikee ::

A aha.. razumem zaj.. nisem vedel tega ker ze dolgo nisem v assemblerju delal. Sicer pa se mi zdi to nepotrebno in brezveze potratno.. vsaj za assembler.. ker vrjetno, da lahko zracuna MOD 32 je uporablen vrjetno dodatno se &, ki bi ti zamaskiral bite nad 5. Ker pa vecina, ki bi shiftala tak ve kaj dela bi to v kaksnih 95% pomenlo nepotrebno dodatno racunanje.. kar se mi zdi za assembler nesprejemljivo. Mogoce bi se pa najsel verjetno tudi kaksen primer, kjer bi se to znalo izkoristit.

Phil ::

A ni pri nekaterih CPU-jih shiftanje narejeno krožno. Da se ti 0-ti ali x-ti (x=velikost registra) bit pri shiftu (lev/ desno) pomakne v C-bit in obratno. Vsaj na MC6803 se mi zdi da je tako (je že nekaj let mimo odkar sem se učil).
recimo:

ldaa #%00000001
rora // a=00000000 C=1
rora // a=10000000 C=0
?
LP

Quikee ::

kolko vem rora pomeni rotate right a .. kar pa ni isto kot shift right.. mislim, da obstaja tudi kaksen ukaz za shift right a. Sem se tudi ucil 6803 assembler in se ne spomnim vec.. =)

Phil ::

Imaš prav ja. shift!=rotate

Rotate instructions are similar to shift instructions, ecept that rotate instructions are circular, with the bits shifted out one end returning on the other end. Rotates can be to the left or right. Rotates can also employ an extend bit for multi-precision rotates.
LP

Thomas ::

Ja, različni procesorji tole različno, zato pa C++ nima standarda. Jest pa vem, da je zdej treba Critticall popravt, ker privzema Intel definicijo. No good!

Vesoljc ::

bad design, a? ;)
Abnormal behavior of abnormal brain makes me normal...

Thomas ::

Ja, bad design je tole. SHIFT LEFT X, 300 bi moralo pomeniti, da se vsi biti zgubijo, če je spremenljivka 300 ali manj bitna.

Bad design, ja.

Ampak tudi C++ bi to moral to pohendlat. 0 je rezultat, če se šifta nekam za tri gore. Ne pa kr neki. ;)

OwcA ::

C++ takšne zablode v veliki meri rešuje tako, da jih zvali na programerje, češ, v peskovnik vam nasujemo še operatorjev, zabavajte se. ;)
Otroška radovednost - gonilo napredka.

64202 ::

> Ja, različni procesorji tole različno, zato pa C++ nima standarda. Jest pa vem, da je zdej treba Critticall popravt, ker privzema Intel definicijo. No good!

Na cemu pa to krepne?

Aja, standard si bral. Ma to so oni pomoje noter pustil kao undefined, zato ker je na pdp-6.66 delalo narobe, pa so vseen hotel imet hitr pa compliant compiler za to platformo :).

Zgodovina sprememb…

  • spremenilo: 64202 ()

snow ::

Če šhiftaš 32 bitno cifro najprej za 20 pa pol še za 20, je ok, če pa naenkrat (40) pa je undefined. Hmm. Bad ja.
Random mutation plus nonrandom cumulative natural selection - Richard Dawkins

Thomas ::

64202

> Na cemu pa to krepne?

snow

> Če šhiftaš 32 bitno cifro najprej za 20 pa pol še za 20, je ok, če pa naenkrat (40) pa je undefined.

:)

Ja ... na Intelih (mislim, da tudi na AMD) je to tako, da shift za 40 bitov je shift za (40 mod 32) je za 8 bitov!

Tako se zadeva scompilira za Intel/AMD. C++ standardi (ki pa niso samo za te platforme) pa se nekako nočejo opredeliti, kako naj bi bilo!

Quikee ::

"Če šhiftaš 32 bitno cifro najprej za 20 pa pol še za 20, je ok, če pa naenkrat (40) pa je undefined."
Hehe.. ja no... ni OK ce 2x shiftas 32 bitno stevilo za 20 =)... vseeno si shiftal 8x prevec od tega kolko bi naj blo smiselno. =) Sicer jaz se ne bi ubadal s tem prevec... tisti, ki bo uporabljal binarni shift bo pac moral vedet kako stvar natancno deluje in da shiftanje vec kot je potrebno je pac nesmiselno. Seveda bi pa rajsi, da prevajalnik javi warning v taksnem primeru in ne, da se vrednost spremenljivke postavi v nedefinirano stanje.

Thomas ::

SHL 1,20
SHL 1,20

ni isto kot

SHL 1,40.

Pač pa je

SHL 1,40

isto kot

SHL 1,8!


To pri Intelu, ki uporabi samo spodnjih 5 bitov od argumenta, za katerega naj bi šiftali.

Pri 64 bitnih procesorjih bodo rabili pa spodnjih 6 bitov? Najbrž.

Kako je bilo pa pri 16 bitnih procesorjih? Rabili so samo spodnje 4 bite argumenta.

Tukaj se splošnost C++ in realnost procesorske arhitekture nekoliko stepeta.

Gundolf ::

C++ je pač narejen tako, da uporablja arhitekturo, ki mu je na voljo. Ne sprašuje se o omejitvah shifta, seštevanja (ali kje piše, da pri seštevanju prevelikih števil nujno pride do overflowa in ne do zabitja v najvišjo možno vrednost) in podobnih for, na katere lahko pozabimo v vsakdanjem življenju. Tudi ga briga little endian / big endian - z njim se tudi lahko opečeš, če poznaš le intelovo arhitekturo. Se pač sklepa da znajo pogramerji obiti te težave, kadar je to treba, drugače jih pa sam jezik ne ovira z avtomatskim preverjanjem vsega živega. Če mene vprašate mi je to zelo všeč. Ohranjaš pač nek stik z assemblerjem (na srečo zelo oddaljen stik).

Če hočete varnost pred 'skritimi' forami potem imate tu pač druge jezike.

64202 ::

Zgornje bite bi zvezal v en signal, ki ti potem nrdi avtomatsko 0 in to je to. Matr so procesorji neprijazni :D

Thomas ::

> Zgornje bite bi zvezal v en signal, ki ti potem nrdi avtomatsko 0 in to je to.

Točno tako! Potem C++ ne bi imel problemov in tudi bi bilo povsem logično. Odpihnilo je vse bite ven, če smo za preveč pošiftali, ne pa da shift pravzaprav dela čudno.

Vesoljc ::

in kako se bos lotil fixa?
Abnormal behavior of abnormal brain makes me normal...

Gundolf ::

Pa ne pozabimo, da bi lahko deloval tudi na negativne številke.

Samo mislim da tale omejitev izhaja iz tega, da so prvi procesorji (tam nekje do 286) znali le shiftanje s konstanto in je bilo to konstanto veliko bolj elegantno zapisati kot 4 bitno stevilo namesto kot 16 bitno. Razširitev je prišla tako, da se je dalo shiftati z registrom, ki pa je najverjetneje 'klical' isto mikrokodo (ali uporabili isti del procesorja) kot shiftanje s konstanto in zato uporabil le 4 bite iz 16 bitnega registra. To se je potem po intelovo vleklo naprej zaradi kompatibilnosti s staro kodo. Lahko pa da se motim, to je le moje mišljenje od kod ta nesmisel.

Thomas ::

> in kako se bos lotil fixa?

Žal nimam pametne ideje. Da ostane tako kot je - Intel like - je nekoliko bedno. Ampak ostale variante so pa riskantne.

Quikee ::

"Pa ne pozabimo, da bi lahko deloval tudi na negativne številke."
Kako to mislis za negativne.... da bi bil shift right -vrednost = shift left vrednost?? To po moje ne bi bilo dopustno... ker je potem ukaz zavajujoc.

Thomas ::

Hja .. zdej je problem. Po moje bi moralo biti že od začetka takole:

SHIFT Number, Bits [Rotate OFF|ON]

Torej da en ukaz šifta kolikor mu je zapovedano, pa da se ven padajoči biti po želji vračajo na drugi strani.

Quikee ::

Hm... zakaj ?? Brezveze bi naredo atomarno operacijo bolj kompleksno.. zdaj jo se pa vedno lahko naredis po zelji.. ce to hoces/rabis.

Gundolf ::

Lahko pozabiš C++ operatorje in uvedeš svoje. shift(int& num, int byNum), rotate(int& num, int byNum), shiftArithmetic(int& num, int byNum).

Gundolf ::

Quikee - zakaj zavajujoč? Saj je prištevanje negativnega števila v bistvu tudi le odštevanje. Pa je povsem dopustno. Če gledaš shift matematično je to le množenje s potenco od 2 (shift A, B = A * 2^B). Nobenega problema z negativnimi števili.

Quikee ::

Ja ce bi bil samo operator shift bi blo OK... samo ne mores ti met operator shift left, ki bi ti v primeru negativnega stvila shifto v desno.
Recimo, da bi se zgubil pa bi me vpraso za pot in bi ti rekel tukaj mores it levo tukaj pa desno bi me razumel. Kaj pa ce bi ti rekel tukaj mores it ne desno in tukaj ne levo.. vrjetno bi bil malo zmeden ne ? =)

Aja.. pa nisem rekel, da je nepravilno.. samo, da je lahko zavajujoce in za moje pojme uporaba ukaza na tak nacin ne bi bila lepa.. ce je shift left pol se more shiftat samo v levo in ne pod dolocenimi pogoji tudi desno.

Zgodovina sprememb…

  • spremenil: Quikee ()

BigWhale ::

Kaksna korist je shiftanje v minus? Mislim, prakticna korist.

zerox ::

Maybe pisanje grde tricky kode pri kateri se lahko izogne uporabi if stavka in mogoče še množenja z -1 :\

64202 ::

> Hm... zakaj ?? Brezveze bi naredo atomarno operacijo bolj kompleksno.. zdaj jo se pa vedno lahko naredis po zelji.. ce to hoces/rabis.

Dokler bi jo procesor naredil v enem ciklu, je se vedno "atomarna". Ce to delas na roke v C-ju, zgubis recimo 10x na hitrosti. CISC rulez :D

Quikee ::

Hehe.. sej kdo je reko, da jo mores napisat v C++... cisto enostavno lahko zivis z sedanjim shift left in shift right... ce ti pa kaj ne pase pa si pac napises svojo.. in tudi vedel bos da bo 10x dlje trajalo, da se taksna operacija izrsi torej je vrjetno ne bos uporablal za kaksne hude algoritme, ki se morajo izvrsit kar se da najhitreje.
Polek tega zakaj bi se mucli pa brezveze komplicirali s tako instrukcijo v procesorju.. ce z njo ne pridobis cisto nic.. le nepotrebno bi povecala jedro procesorja.. kar bi preneslo vecje stroske izdelave za brezveze in ce bi to naredili z vec instrukcijami tudi vecjo gretje samega processorja. Po vsej vrjetnosti pa bi rabla tudi vec kot en cikel, da se izvrsi.. ker vecina instrukcij rabi vec kot en cikel.
Polek tega rotate ni pol tolko uporaben kot shift in ga je brezveze sploh metat v isti kos kot shift (mislim, da x86 rotate instrukcije sploh nima). Ce ga pa kdo rabi pa bo si bo ze napisal operacijo s pomocjo drugih binarnih operatorjev.

Keep it simple.

64202 ::

> Hehe.. sej kdo je reko, da jo mores napisat v C++... cisto enostavno lahko zivis z sedanjim shift left in shift right... ce ti pa kaj ne pase pa si pac napises svojo.. in tudi vedel bos da bo 10x dlje trajalo, da se taksna operacija izrsi torej je vrjetno ne bos uporablal za kaksne hude algoritme, ki se morajo izvrsit kar se da najhitreje.

Thomas ima hud algoritem :)

Sej to je the point, zdaj bo mogu napisat 10x pocasnejs workaround.

Quikee ::

Jah pa kaj.. vecini pa vredu ustreza in se sploh ne sekirajo glede nekega bogega shifta na kak nacin je narejen.. glavno da naredi to kar mora. Skoda ker se ne da mikrokoda procesorja spreminjat... pol bi si vsak sam instrukcije piso kak se bi mu zazdelo. =))

64202 ::

Pa backward compatibility ven dal in hkrati s tem podvojil velikost L2 cache-a :).

64202 ::

> Jah pa kaj.. vecini pa vredu ustreza in se sploh ne sekirajo glede nekega bogega shifta na kak nacin je narejen.. glavno da naredi to kar mora.

No, meni se zdi da dela narobe. Sem do zdaj mislil da (1 << 33) vrne 0, kar je bolj prav IMHO. Klinc pa tistih par linij v jedru, ne bi nobenga pobralo. Primerjaj to recimo s floating point mnozenjem/deljenjem.

Realnost je pac taka, da si pogosto prisiljen pisati zadevo v jeziku, ki ti ne pase ali pa ze samo po sebi ne ustreza nalogi. Jaz za stvari, ki jih zdaj pocnem ziher ne bi izbral c++-sa, pa je treba pac narest v njemu. Lahko grem kar gledat, kje mam bug zaradi tega :(

Zgodovina sprememb…

  • spremenilo: 64202 ()

Gundolf ::

Ne vem kaj vas moti pri shift left za -2. Meni se zdi povsem jasno. Še vedno mislim da popolnoma drži analogija z seštevanjem. Imaš isto ukaz add, ki pa veselo sprejme negativna števila (pravzaprav x86 add sploh ne razlikuje med unsigned in signed int ampak pustimo to). Tudi pri tem ukazu bi lahko rekel, da je zavajujoče da pod določenimi pogoji zmanjša število, saj se že iz imena ukaza vidi, da bo nekaj 'dodal' k številu.

Shift left pač rečeš zato, ker iz same besede shift ni razvidno kam shiftaš. Če ti pa isti ukaz zmore tudi shift v desno pa še toliko bolje. Seveda obdržiš tudi shift right, ki zna tudi shiftat levo. Isto kot obdržiš add in sub.

Zgodovina sprememb…

  • spremenil: Gundolf ()

Gundolf ::

64202: 1<<33 = 0, je že prav dokler gre za 32bitne cifre (čeprav C++ na x86 arhitekturi tega ne ve - ojej neumni C++) ampak 100% to ne bo več 0, ko boš isti program prevedel na 64 bitni arhitekturi. No povedat hočem, da C++ standard NE določa koliko bitni je tip int (lahko sicer privzameš da je vsaj 32), zato je že na začetku tako shiftanje in predvidevanje rezultata stvar slabega designa. Pravzaprav je vsako izkoriščanje 'napak' v posamezni procesorski arhitekturi slabo (recimo seštevanje pri katerem veš, da bo prišlo do overflowa). Razen če je program namenjen izključno eni arhitekturi in res veš kaj delaš.

Je pa problem, da živ bog (vsaj pri nas v Sloveniji) ne zna učiti C++a in ga potem nekateri programerji za nič na svetu ne znajo pravilno uporabit. Pa sori 64202, te ne mislim kritizirati, tudi večina tegale ne leti nate.

64202 ::

64202: 1<<33 = 0, je že prav dokler gre za 32bitne cifre (čeprav C++ na x86 arhitekturi tega ne ve - ojej neumni C++) ampak 100% to ne bo več 0, ko boš isti program prevedel na 64 bitni arhitekturi. No povedat hočem, da C++ standard NE določa koliko bitni je tip int (lahko sicer privzameš da je vsaj 32), zato je že na začetku tako shiftanje in predvidevanje rezultata stvar slabega designa. Pravzaprav je vsako izkoriščanje 'napak' v posamezni procesorski arhitekturi slabo (recimo seštevanje pri katerem veš, da bo prišlo do overflowa). Razen če je program namenjen izključno eni arhitekturi in res veš kaj delaš.

sizeof(int) == 4, torej bi vsaj tukaj clovek pricakoval :). A potem je to maslo C++ standarda? Intel torej zna (1 << 33) -> 0? Ja, vem bolj malo o asmju :8).

Pa skoraj normalno na winsih je, da vzames ... hm kak je ze klic, un milisekundni cas, ki je unsigned int. Potem ce naredis a - b, dobis se vedno pravilen pozitiven cas, tudi ce je bil overflow. Ce je bilo vmes manj kot 2^32 ms seveda. Talking about bad practice? :)

Thomas ::

1<<33 = 2 !

Tko pravi Intel, zato tko pravi Critticall. BAD!

C++ standard se zaveda te pomanjkljivosti in pravi 1<<33 = BOHVEKOLK.

Ne vem komu naj jokam in kam naj se pritožim. Še razmišljam, kaj narest.



Seveda človeški programer ne dela takih fint kot naprimer a=a>>a; EA pa komot, isto kot a=a+a;. Samo znotraj Intel standarda je to sprijeno, ker 100<<100 je enako 1600. Heh ...

OwcA ::

Za hitre packanje je bog ustvaril #define, #pragma, #ifdef ... ;)
Otroška radovednost - gonilo napredka.

Gundolf ::

Thomas je dobro povedal: C++ standard se zaveda te pomanjkljivosti in pravi 1<<33 = BOHVEKOLK.
Intel pravi da je to enako 2. AMD 64 bi verjetno rekel da je to 2^32 (če bi delal v 64 bitnem načinu). Na tastarih Macih bi bilo morda 0.

64202: dvomim, da ti v svojem programu pogledaš, če je sizeof(int)==4 preden greš karkoli delat :D. Pač veš da delaš na IA32 in da je do 64 bitov v osebnih računalnikih še daleč.

Dal pa si lep primer za bad practice ja. Se moraš zanašati na to, da je poteklo le malo časa od prejšnje meritve. Drugače pa to ni tako problematično, ker ti bo v primeru 64 bitnega unsigned inta delalo še vedno povsem enako. Le v primeru malo drugačne arhitekture (kjer pa winsi tako ali tako ne delajo) bo crknilo. Primer za to bi bil recimo procesorski exception ob overflowu, ki ti lepo crasha program, ker ga ne pričakuješ.

Thomas: zakaj ne definiraš neke funkcije Shift() in z njo nadomestiš istoimenski operator? Res da bi potlej moral definirati neko standardno knjižnico (z definicijo Shifta), ki bi jo uporabljali vsi programi narejeni s Criticallom ;)
«
1
2


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Assembler razumevanje programa

Oddelek: Programiranje
71933 (824) BivšiUser2
»

1st web project... speed up?

Oddelek: Programiranje
172561 (1925) galu
»

Superračunalnik za štiri tisoč evrov (strani: 1 2 )

Oddelek: Novice / Znanost in tehnologija
6712245 (6429) jype
»

[C] generator naključnih števil

Oddelek: Programiranje
363303 (2821) Thomas
»

[C] bitni operator (strani: 1 2 3 )

Oddelek: Programiranje
1125228 (4061) Thomas

Več podobnih tem