Vra

In C, is die verskuiwing operateurs (<<, >>) rekenkundige of logiese?

Was dit nuttig?

Oplossing

Volgens K & R 2de uitgawe die resultate is implementering-afhanklike vir reg skofte van onderteken waardes.

Wikipedia sê dat C / C ++ 'gewoonlik' implemente 'n rekenkundige verskuiwing op onderteken waardes.

Eintlik moet jy óf toets jou samesteller of nie staatmaak op dit. My VS2008 hulp vir die huidige MS C ++ vertaler sê dat hulle samesteller doen 'n rekenkundige verskuiwing.

Ander wenke

Wanneer die verskuiwing van links, is daar geen verskil tussen rekenkundige en logiese verskuiwing. Wanneer die verskuiwing van reg, die tipe verskuiwing hang af van die tipe van die waarde verskuif.

(As agtergrond vir dié lesers wat nie vertroud met die verskil, 'n "logiese" reg verskuiwing deur 1 bietjie verskuif al die stukkies van die reg en vul in die linker bietjie met 'n 0. 'n "rekenkundige" shift laat die oorspronklike waarde in die linker bietjie. die verskil raak belangrik wanneer die hantering van negatiewe nommers.)

Wanneer verskuiwing 'n ongetekende waarde, die >> operateur in C is 'n logiese verskuiwing. Wanneer die verskuiwing van 'n getekende waarde, die >> operateur is 'n rekenkundige verskuiwing.

Byvoorbeeld, in die veronderstelling n 32 bit masjien:

signed int x1 = 5;
assert((x1 >> 1) == 2);
signed int x2 = -5;
assert((x2 >> 1) == -3);
unsigned int x3 = (unsigned int)-5;
assert((x3 >> 1) == 0x7FFFFFFD);

TL; DR

Oorweeg i en n onderskeidelik die links en regs operande van 'n verskuiwing operateur; die tipe i, nadat heelgetal bevordering, word T. Veronderstelling n te wees in [0, sizeof(i) * CHAR_BIT) - undefined anders - ons het hierdie gevalle:

| Direction  |   Type   | Value (i) | Result                   |
| ---------- | -------- | --------- | ------------------------ |
| Right (>>) | unsigned |    ≥ 0    | −∞ ← (i ÷ 2ⁿ)            |
| Right      | signed   |    ≥ 0    | −∞ ← (i ÷ 2ⁿ)            |
| Right      | signed   |    < 0    | Implementation-defined†  |
| Left  (<<) | unsigned |    ≥ 0    | (i * 2ⁿ) % (T_MAX + 1)   |
| Left       | signed   |    ≥ 0    | (i * 2ⁿ) ‡               |
| Left       | signed   |    < 0    | Undefined                |

† meeste opstellers implementeer hierdie as rekenkundige verskuiwing
‡ ongedefinieer as waarde oorloop die tipe resultaat T; bevorder tipe i


Shifting

Eerste is die verskil tussen logiese en rekenkundige skofte van 'n wiskundige oogpunt, sonder om bekommerd te wees oor die tipe data grootte. Logiese skofte altyd vul weggegooi stukkies met nulle terwyl rekenkundige verskuiwing vul dit met nulle net vir links skuif, maar vir reg skuif dit afskrifte die MSB sodoende die teken van die operand behoud (met die aanvaarding 'n twee se komplement kodering vir negatiewe waardes).

Met ander woorde, logiese verskuiwing kyk na die verskuif operand as net 'n stroom bisse en beweeg hulle, sonder pla oor die teken van die gevolglike waarde. Rekenkundige verskuiwing kyk na dit as 'n (onderteken) getal en bewaar die teken as skofte gemaak.

'n links rekenkundige verskuiwing van 'n aantal X deur N is gelykstaande aan vermenigvuldig X deur 2 n en is dus gelykstaande aan logiese links skuif; 'n logiese verskuiwing sou ook dieselfde resultaat gee sedert MSB in elk geval val af die einde en daar is niks om te bewaar.

'n reg rekenkundige verskuiwing van 'n aantal X deur N is gelykstaande aan afdeling van X heel getal deur 2 n SLEGS as X is nie-negatiewe! Integer afdeling is niks anders as wiskundige afdeling en ronde na 0 ( TRUNC ).

Vir negatiewe getalle, verteenwoordig deur twee se komplement enkodering, verskuiwing reg deur N stukkies het die effek van wiskundig deel deur 2 n en afronding tot -∞ ( vloer ); dus reg verskuiwing is anders vir nie-negatiewe en negatiewe waardes.

  

vir X ≥ 0, X >> N = X / 2 n = TRUNC (X ÷ 2 n )

     

vir X <0, X >> N = vloer (X ÷ 2 n )

waar ÷ is wiskundige afdeling, / is heelgetal afdeling. Kom ons kyk na 'n voorbeeld:

  

37) 10 = 100101) 2

     

37 ÷ 2 = 18.5

     

37/2 = 18 (afronding 18.5 teenoor 0) = 10.010) 2 [gevolg van rekenkundige reg verskuiwing]

     

-37) 10 = 11011011) 2 (oorweging van 'n twee se komplement, 8-bit verteenwoordiging)

     

-37 ÷ 2 = -18,5

     

-37/2 = -18 (afronding 18.5 teenoor 0) = 11101110) 2 [nie die gevolg van rekenkundige reg verskuiwing]

     

-37 >> 1 = -19 (afronding 18.5 teenoor -∞) = 11101101) 2 [gevolg van rekenkundige reg verskuiwing]

As Guy Steele het daarop gewys , hierdie teenstrydigheid het gelei tot href="http://en.wikipedia.org/wiki/Arithmetic_shift" rel="noreferrer"> foute . Hier non-negatiewe (wiskunde) gekarteer kan word om unsigned en onderteken nie-negatiewe waardes (C); beide behandel dieselfde en regs-skuif hulle word gedoen deur heelgetal afdeling.

So logiese en rekenkundige ekwivalent in links-verskuiwing en vir nie-negatiewe waardes in reg verskuif; dit is in die regte verskuiwing van negatiewe waardes wat hulle verskil.

Operand en Resultaat Tipes

Standard C99 §6.5.7

  

Elk van die operande sal hê heelgetal tipes.

     

Die heelgetal promosiesuitgevoer op elk van die operande. Die tipe van die gevolg is dat van die bevorder links operand. As die waarde van die reg operand negatief of groter as of gelyk aan die wydte van die bevorder links operand, die gedrag is ongedefinieerd.

short E1 = 1, E2 = 3;
int R = E1 << E2;

In die bogenoemde uittreksel, beide operande word int (as gevolg van heelgetal bevordering); As E2 was negatief of E2 ≥ sizeof(int) * CHAR_BIT dan die operasie is ongedefinieerd. Dit is omdat die verskuiwing van meer as die beskikbare stukkies is sekerlik gaan oorloop. Het R verklaar as short, sou die int gevolg van die verskuiwing operasie implisiet omgeskakel word na short; 'n vernouing bekering, wat kan lei tot-implementering gedefinieer gedrag as die waarde is nie representeerbaar in die tipe bestemming.

Left Shift

  

Die gevolg van E1 << E2 is E1 links verskuif E2 bietjie posisies; ontruim stukkies is gevul met nulle. As E1 het 'n ongetekende tipe, die waarde van die resultaat is E1 × 2 E2 , verminder modulo een meer as die maksimum waarde representeerbaar in die tipe resultaat. As E1 het 'n getekende tipe en nie-negatiewe waarde, en E1 × 2 E2 is representeerbaar in die tipe resultaat, dan is dit die gevolg waarde; anders, die gedrag is ongedefinieerd.

As links verskuif is dieselfde vir beide, is die ontruim stukkies net gevul met nulle. Dit verklaar dan dat vir beide unsigned en onderteken tipes dis 'n rekenkundige verskuiwing. Ek is dit die interpretasie as rekenkundige verskuiwing sedert logiese skofte nie die moeite doen oor die waarde wat deur die stukkies, dit net kyk na dit as 'n stroom bisse; maar die standaard gesprekke nie in terme van stukkies, maar deur die definisie van dit in terme van die resultate wat verkry word deur die produk van E1 met 2 waarde E2 .

Die caveat hier is dat vir ondertekening tipes die waarde moet nie-negatiewe en die gevolglike waarde moet representeerbaar in die tipe resultaat wees. Anders sal die operasie is ongedefinieerd. Die tipe gevolg sou die tipe van die E1 wees na die toepassing van integrale bevordering en nie die bestemming (die veranderlike wat gaan die resultaat hou) tik. Die gevolglike waarde is implisiet omgeskakel word na die tipe bestemming; indien dit nie representeerbaar in daardie soort, dan die omskakeling is-implementering omskryf (C99 §6.3.1.3 / 3).

As E1 is 'n getekende tipe met 'n negatiewe waarde dan die gedrag van links verskuiwing is ongedefinieerd. Dit is 'n maklike pad na undefined gedrag wat maklik kan kry oor die hoof gesien.

Right Shift

  

Die gevolg van E1 >> E2 is E1 regs-skuif E2 bietjie posisies. As E1 het 'n ongetekende tipe of as E1 het 'n getekende tipe en 'n nie-negatiewe waarde, die waarde van die resultaat is die integrale deel van die kwosiënt van E1 / 2 E2 . As E1 het 'n getekende tipe en 'n negatiewe waarde, die gevolglike waarde is-implementering omskryf.

Reg verskuiwing vir unsigned en onderteken nie-negatiewe waardes is redelik reguit vorentoe, die vakante stukkies is gevul met nulle. Vir onderteken negatiewe waardes die gevolg van regs verskuiwing is-implementering omskryf. Dit gesê, die meeste implementering soos GCC en Visual C ++ implementeer regs-skuif as rekenkundige verskuif deur die behoud van die teken bit.

Gevolgtrekking

In teenstelling met Java, wat 'n spesiale operateur >>> vir logiese verskuiwing afgesien van die gewone >> en << het, C en C ++ net rekenkundige verskuif met 'n paar gebiede links ongedefinieerde en-implementering omskryf. Die rede waarom ek hulle ag as rekenkundige is te danke aan die standaard bewoording die operasie wiskundig eerder as die behandeling van die verskuif operand as 'n stroom bisse; Dit is dalk die rede waarom dit daardie gebiede un /-implementering gedefinieer instea laatd van net die definisie van alle gevalle as logiese skofte.

In terme van die tipe verskuiwing jy, die belangrikste ding is die tipe van die waarde wat jy skuif. 'N klassieke bron van foute is wanneer jy 'n letterlike te skuif, sê, 'n masker af stukkies. Byvoorbeeld, as jy wou laat sak jou linkerskouer mees bietjie van 'n ongetekende heelgetal, dan kan jy dalk hierdie probeer as jou masker:

~0 >> 1

Ongelukkig is dit sal jy in die moeilikheid beland omdat die masker al sy stukkies te stel omdat die waarde verskuif sal moet (~ 0) onderteken, is dus 'n rekenkundige verskuiwing uitgevoer. In plaas daarvan, sal jy 'n logiese verskuiwing dwing deur uitdruklik verklaar dat die waarde as unsigned, dit wil sê deur so iets te doen:

~0U >> 1;

Hier is 'n funksie om logiese reg verskuiwing en rekenkundige reg verskuiwing van 'n int in C waarborg:

int logicalRightShift(int x, int n) {
    return (unsigned)x >> n;
}
int arithmeticRightShift(int x, int n) {
    if (x < 0 && n > 0)
        return x >> n | ~(~0U >> n);
    else
        return x >> n;
}

As jy dit doen  - links skuif deur 1 jy vermenigvuldig met 2  - reg verskuiwing deur 1 jy verdeel deur 2

 x = 5
 x >> 1
 x = 2 ( x=5/2)

 x = 5
 x << 1
 x = 10 (x=5*2)

Wel, ek kyk dit op wikipedia , en hulle het dit te sê:

  

C het egter net een regte verskuiwing   operateur, >>. Baie C opstellers kies   wat reg verskuiwing uit te voer na gelang   op watter tipe integer is om   verskuif; dikwels onderteken heelgetalle is   verskuif met behulp van die rekenkundige verskuiwing,   en ongetekende heelgetalle verskuif   met behulp van die logiese verskuiwing.

Dit klink soos dit hang af van jou samesteller. Ook in daardie artikel, kennis dat links verskuiwing is dieselfde vir rekenkundige en logiese. Ek sou aanbeveel doen 'n eenvoudige toets met 'n paar onderteken en unsigned nommers op die grens geval (hoë bietjie stel natuurlik) en sien wat die resultaat is van jou samesteller. Ek sou ook aanbeveel vermy, afhangende van dit wat een of die ander, aangesien dit blyk C het geen standaard, ten minste as dit redelik en moontlik is om so 'n afhanklikheid voorkom.

Van links verskuiwing <<

Dit is 'n manier maklik en wanneer jy die verskuiwing operateur gebruik, dit is altyd 'n bietjie-wyse operasie, so ons kan dit nie gebruik nie met 'n dubbele en dryf operasie. Wanneer ons links skuif een nul, is dit altyd by die minste beduidende bietjie (LSB).

Maar in reg verskuiwing >> moet ons 'n ekstra reël volg en dat reël is "teken bietjie kopie" genoem. Betekenis van "teken bietjie kopie" is as die belangrikste bietjie (MSB) dan is ingestel nadat 'n reg verskuiwing weer die MSB sal stel indien dit weer in te stel dan is dit weer herstel, beteken dat as die vorige waarde is nul dan na weer verskuif die bietjie nul as die vorige bietjie was een dan na die verskuiwing is dit weer een. Hierdie reël is nie van toepassing vir 'n links skuif.

Die belangrikste voorbeeld op reg verskuiwing as jy enige negatiewe getal skuif na regs skuif, dan na 'n paar verskuiwing van die waarde uiteindelik reik na zero en dan na hierdie as verskuiwing hierdie -1 enige aantal kere sal die waarde bly dieselfde. Gaan asseblief.

sal tipies gebruik logiese skofte op ongetekende veranderlikes en vir links-skofte op onderteken veranderlikes. Die rekenkundige reg verskuiwing is die werklik belangrike een, want dit sal teken uitbreiding van die veranderlike.

sal sal dit gebruik wanneer van toepassing, as ander samestellers is geneig om te doen.

GCC doen

  1. vir -ve -> Rekenkundige Shift

  2. Vir + ve -> Logiese Shift

Volgens baie opstellers:

  1. << is 'n rekenkundige links verskuiwing of bis links skuif.
  2. >> is 'n rekenkundige reg shiftor bis reg verskuiwing.
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top