Q (sifferformat)

Q -notationen är ett sätt att specificera parametrarna för ett binärt fixpunktsnummerformat . Till exempel i Q-notation betyder talformatet som betecknas med Q8.8 att fixpunktstalen i detta format har 8 bitar för heltalsdelen och 8 bitar för bråkdelen.

Ett antal andra notationer har använts för samma ändamål.

Definition

Texas Instruments version

Q-notationen, som definieras av Texas Instruments , består av bokstaven Q följt av ett par siffror m . n , där m är antalet bitar som används för heltalsdelen av värdet och n är antalet bråkbitar.

Som standard beskriver notationen signerat binärt fixpunktsformat, där det oskalade heltalet lagras i tvås komplementformat , som används i de flesta binära processorer. Den första biten ger alltid tecknet för värdet (1 = negativ, 0 = icke-negativ), och den räknas inte i parametern m . Det totala antalet bitar w som används är alltså 1 + m + n .

Till exempel beskriver specifikationen Q3.12 ett signerat binärt fixpunktsnummer med ett w = 16 bitar totalt, innefattande teckenbiten, tre bitar för heltalsdelen och 12 bitar som är bråkdelen. Det vill säga ett 16-bitars tecken (tvåkomplement) heltal, som implicit multipliceras med skalfaktorn 2 −12

I synnerhet när n är noll är talen bara heltal. Om m är noll är alla bitar utom teckenbiten bråkbitar; då är intervallet för det lagrade numret från −1,0 (inklusive) till +1 (exklusivt).

M och punkt kan utelämnas, i vilket fall de härleds från storleken på variabeln eller registret där värdet är lagrat . Q12 betyder alltså ett heltal med tecken med valfritt antal bitar, som implicit multipliceras med 2 −12 .

Bokstaven U kan föregås av Q:et för att beteckna ett binärt fixpunktsformat utan tecken . Till exempel beskriver UQ1.15 värden representerade som 16-bitars heltal utan tecken med implicit skalfaktor på 2 −15 , som sträcker sig från 0,0 till (2 16 −1)/2 15 = +1,999969482421875.

ARM-version

En variant av Q-notationen har använts av ARM . I denna variant m -talet teckenbiten. Till exempel skulle ett 16-bitars signerat heltal betecknas Q15.0 i TI-varianten, men Q16.0 i ARM-varianten.

Egenskaper

Upplösningen (skillnaden mellan successiva värden) för en Qm . n eller UQ m . n format är alltid 2 n . Omfånget av representativa värden beror på vilken notation som används:

Omfång av representerbara värden i Q-notation
Notation Texas Instruments notation ARM-notation
Signerad Q m . n −2 m till +2 m − 2 n −2 m −1 till +2 m −1 − 2 n
Osignerad UQ m . n 0 till 2 m − 2 n 0 till 2 m − 2 n

Till exempel kräver ett Q15.1-formatnummer 15+1 = 16 bitar, har upplösning 2 −1 = 0,5, och de representerbara värdena sträcker sig från −2 14 = −16384,0 till +2 14 − 2 −1 = +16383,5. I hexadecimal sträcker sig de negativa värdena från 0x8000 till 0xFFFF följt av de icke-negativa från 0x0000 till 0x7FFF.

Matematiska operationer

Q-tal är ett förhållande mellan två heltal: täljaren lagras, nämnaren är lika med 2 n .

Tänk på följande exempel:

  • Q8-nämnaren är lika med 2 8 = 256
  • 1,5 är lika med 384/256
  • 384 lagras, 256 antas eftersom det är ett Q8-nummer.

Om Q-talets bas ska bibehållas ( n förblir konstant) måste Q-talets matematiska operationer hålla nämnaren konstant. Följande formler visar matematiska operationer på de allmänna Q-talen och . (Om vi ​​betraktar exemplet som nämnt ovan, är är 256.)

Eftersom nämnaren är en potens av två kan multiplikationen implementeras som ett aritmetiskt skift till vänster och divisionen som ett aritmetiskt skift till höger; på många processorer är skift snabbare än multiplikation och division.

För att bibehålla noggrannheten måste de mellanliggande multiplikations- och divisionsresultaten vara dubbel precision och försiktighet måste iakttas vid avrundning av mellanresultatet innan du konverterar tillbaka till det önskade Q-talet.

Med C är operationerna (observera att här hänvisar Q till bråkdelens antal bitar):

Tillägg

    

       
 int16_t  q_add  (  int16_t  a  ,  int16_t  b  )  {  retur  a  +  b  ;  } 

Med mättnad

    

     
     

        
       
          
         
            
      

     
 int16_t  q_add_sat  (  int16_t  a  ,  int16_t  b  )  {  int16_t  resultat  ;  int32_t  tmp  ;  tmp  =  (  int32_t  )  a  +  (  int32_t  )  b  ;  if  (  tmp  >  0x7FFF  )  tmp  =  0x7FFF  ;  if  (  tmp  <  -1  *  0x8000  )  tmp  =  -1  *  0x8000  ;  resultat  =  (  int16_t  )  tmp  ;  returnera  resultat  ;  } 

Till skillnad från flyttal ±Inf är mättade resultat inte klibbiga och kommer att bli omättade när ett negativt värde läggs till ett positivt mättat värde (0x7FFF) och vice versa i den visade implementeringen. I assemblerspråk kan flaggan Signed Overflow användas för att undvika de typcasts som behövs för den C-implementeringen.

Subtraktion

    

       
 int16_t  q_sub  (  int16_t  a  ,  int16_t  b  )  {  retur  a  -  b  ;  } 

Multiplikation



 

  

	     
	      
	  


    

     
     

         
    
      
    
        

     
 //  förberäknat värde:  #define K (1 << (Q - 1))  // saturate till intervallet int16_t  int16_t  sat16  (  int32_t  x  )  {  if  (  x  >  0x7FFF )   returnera  0x7FFF  ;  annars  om  (  x  <  -0x8000  )  returnerar  -0x8000  ;  annars  returnerar  (  int16_t  )  x  ;  }  int16_t  q_mul  (  int16_t  a  ,  int16_t  b  )  {  int16_t  resultat  ;  int32_t  temp  ;  temp  =  (  int32_t  )  a  *  (  int32_t  )  b  ;  // resultattyp är operandens typ  // Avrundning; mittvärdena avrundas uppåt   temp  +=  K  ;  // Korrigera genom att dividera med bas och mättat resultat  resultat  =  sat16  (  temp  >>  Q  );  returnera  resultat  ;  } 

Division

    

    
         
    
    
       0    0    0    0    
                
      
                
    
       
 int16_t  q_div  (  int16_t  a  ,  int16_t  b  )  {  /* förmultiplicera med basen (Uppskala till Q16 så att resultatet blir i Q8-format) */  int32_t  temp  =  (  int32_t  )  a  <<  Q  ;  /* Avrundning: mellanvärdena avrundas uppåt (nedåt för negativa värden). */   /* ELLER jämför de mest signifikanta bitarna dvs if (((temp >> 31) & 1) == ((b >> 15) & 1)) */ if ((  temp  >  =  &&  b  >  =  )  ||  (  temp  <  &&  b  <  ))  {  temp  +=  b  /  2  ;  /* ELLER skift 1 bit dvs temp += (b >> 1); */   }  annat  {  temp  -=  b  /  2  ;  /* ELLER skift 1 bit dvs temp -= (b >> 1); */   }  return  (  int16_t  )(  temp  /  b  );  } 

Se även

Vidare läsning

externa länkar