Fråga om >> i C
Fråga om >> i C
Vad betyder >> i följande rad?
t1 = ((long)t1*(long)volts) >> 15;
Har jag tolkat det rätt om t1 sätts till T1*volts enbart om värdet är större än 15, en förenklad version av en if-sats alltså?
t1 = ((long)t1*(long)volts) >> 15;
Har jag tolkat det rätt om t1 sätts till T1*volts enbart om värdet är större än 15, en förenklad version av en if-sats alltså?
Re: Fråga om >> i C
t1 multipliceras med volt och skiftas sedan binärt till höger (mindre värde) med 15 steg.
65536 >> 15 ger resultatet 2.
Om t1=10 000 och volt=12 så blir det först 120 000 som sedan skiftas 15 steg åt höger vilket ger resultatet 3.
65536 >> 15 ger resultatet 2.
Om t1=10 000 och volt=12 så blir det först 120 000 som sedan skiftas 15 steg åt höger vilket ger resultatet 3.
Re: Fråga om >> i C
Ja, om man tolkar det som skiftas som ett "värde".
Det kan ju vara något helt annat också. Men i exemplet
så ser det ju ut som att en uppmätt spänning ska skalas...
Det kan ju vara något helt annat också. Men i exemplet
så ser det ju ut som att en uppmätt spänning ska skalas...
Re: Fråga om >> i C
Kan tilläggas att en anledning att man ofta använder shiftning när man ska dividera eller multiplicera med en faktor som är en jämn tvåpotens är att det är snabbare på många processorer (som saknar hårdvara för div och mul).
Re: Fråga om >> i C
Speciellt på de som har en "barrel shifter" där antalet steg
som det ska shiftas är en parameter i shift-kommandot.
Alltså *en* 15-stegs shift istället för 15 1-stegs shift. Inte så
vanligt på 8-bitare, men på 16-bitars brukar de finna med.
som det ska shiftas är en parameter i shift-kommandot.
Alltså *en* 15-stegs shift istället för 15 1-stegs shift. Inte så
vanligt på 8-bitare, men på 16-bitars brukar de finna med.
Re: Fråga om >> i C
Ytterligare ett tillägg, moderna (nåja, hyffsat omoderna också ..) C-kompilatorer gör den här formen av optimering själva, det går alltså lika bra att skriva " / 32768" och få ut samma maskinkod. Som bonus blir koden mer lättläst och enklare att porta.
Re: Fråga om >> i C
En sak som kan förvirra här är hur unsigned och signed hanteras.
De flesta implementerar >> på en unsigned som logisk: dvs den fyller på med 0:or längst upp och >> som en logisk signed shiftar den ner men behåller tecknet(högsta bit:en bestämmer vad som ska fyllas ut med)
De flesta implementerar >> på en unsigned som logisk: dvs den fyller på med 0:or längst upp och >> som en logisk signed shiftar den ner men behåller tecknet(högsta bit:en bestämmer vad som ska fyllas ut med)
Re: Fråga om >> i C
Vilket gör att höger shift inte är samma sak som division för negativa tal. Kompilatorn kan därmed inte optimera bort en division av signed så länge den inte samtidigt kan garantera att något fall där de skiljer åt inte kan inträffa.
Kod: Markera allt
{
signed a=-1,b=-1;
a /= 2;
b >>= 1;
// a == 0, b == -1 om implementerat som aritmetisk skift, men kan vara vad som helst
}
Re: Fråga om >> i C
Kompilaton (och eventuellt processorn) måste kunna skilja på
en "logic shift" och en "arithmetic shift".
en "logic shift" och en "arithmetic shift".
Re: Fråga om >> i C
hur ska den kunna skilja på det om det bara finns en symbol >> ?
I assembler finns det ju ofta två sorters shift åt höger (beror lite på processorfamilj):
Logic shift right och rotate right.
Logic shift lägger alltid i en nolla längst upp. Rotate lägger i värdet i carry-flaggan (och plockar värdet från lägsta biten och lägger i carry). I C finns det bara motsvarigheten för logic shift om man använder >> på ett "unsigned int". Detta motsvaras exakt av division med en tvåpotens. Alltså kan kompilatorn optimera detta.
Rotate finns givetvis inte då "carry" inte existerar i C.
Vad som däremot sker i ett "signed int" beror lite på kompilatorn, men de flesta verkar låta högsta biten ligga kvar oförändrad, viket ger ett resultat mycket nära division, men inte exakt. Det går att korrigera med lite villkor och ev. addition med ett - och på så vis kan man få en optimerad kod även när man ska dividera signed int med en tvåpotens.
I assembler finns det ju ofta två sorters shift åt höger (beror lite på processorfamilj):
Logic shift right och rotate right.
Logic shift lägger alltid i en nolla längst upp. Rotate lägger i värdet i carry-flaggan (och plockar värdet från lägsta biten och lägger i carry). I C finns det bara motsvarigheten för logic shift om man använder >> på ett "unsigned int". Detta motsvaras exakt av division med en tvåpotens. Alltså kan kompilatorn optimera detta.
Rotate finns givetvis inte då "carry" inte existerar i C.
Vad som däremot sker i ett "signed int" beror lite på kompilatorn, men de flesta verkar låta högsta biten ligga kvar oförändrad, viket ger ett resultat mycket nära division, men inte exakt. Det går att korrigera med lite villkor och ev. addition med ett - och på så vis kan man få en optimerad kod även när man ska dividera signed int med en tvåpotens.
Re: Fråga om >> i C
Fast den borde ju kunna gå på om vänsteroperanden är unsigned eller inte. Vill man nu
Logical-shifta en signed får man cast:a till unsigned. och vice verca.
Logical-shifta en signed får man cast:a till unsigned. och vice verca.
Re: Fråga om >> i C
hmmm.... jag har faktiskt inte tänkt på det förut, men kan shiftoperatorerna ( << och >> ) ta negativa tal på höger sida?
I så fall skulle 1 >> (-3) vara detsamma som 1 << 3 och resultatet blir 8.
I så fall skulle 1 >> (-3) vara detsamma som 1 << 3 och resultatet blir 8.
Re: Fråga om >> i C
Nej (generellt sett).
C99 avsnitt 6.3.7 Bitwise shift operators, punkt 3 skrev: If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.