uint16_t interp2(const uint8_t x, const uint8_t A, const uint8_t B, const uint8_t M)
{
uint16_t V = B + (A-B)*x/M;
return V;
}
Ger 3 multiplikationer. Jag antar att det beror på att man i det övre fallet själv tar ansvar för att A-B inte slår runt. Går detta att utläsa av standarden?
EDIT: Ändrade AB från signed till unsigned
Det första exemplet måste ju göra en 8-bit multiplikation, så resultatet blir antagligen fel. Du behöver tala om för kompilatorn att högerledet ska utföras med 16 bitar.
Man måste väl göra 3 mul på en 8-bit processor ifall produkten och faktorerna är 16-bit.
Tror att avr-gcc går utanför standarden för att koden ska bli effektivare på en AVR.
EDIT: glöm detta inlägg. Nu fattar jag. Mul-instruktionen ger ju ett 16-bit resultat, och dina faktorer var 8 bit.
uint16_t interp2(const uint8_t x, const uint8_t A, const uint8_t B, const uint8_t M)
{
uint16_t V = B + (A-B)*x/M;
return V;
}
Ger 3 multiplikationer. Jag antar att det beror på att man i det övre fallet själv tar ansvar för att A-B inte slår runt. Går detta att utläsa av standarden?
EDIT: Ändrade AB från signed till unsigned
Förklaringen går mycket riktigt att hitta i standarden, närmare bestämt under kapitel 6.3.1.1 Boolean, characters, and integers paragraf 2: "The following may be used in an expression wherever an int or unsigned int may
be used:
— An object or expression with an integer type whose integer conversion rank is less
than or equal to the rank of int and unsigned int.
— A bit-field of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the integer
promotions.48) All other types are unchanged by the integer promotions."
Som vi vet är en int 16 bitar i avr-gcc, så för det nedre exemplet ger detta oss att: uint16_t V = B + ((int16_t)A-(int16_t)B)*x/M;
(int16_t)A-(int16_t)B kommer givetvis även de resultera i en int16_t
För det övre exemplet får vi: uint16_t V = B + ((int16_t)AB)*x/M;
Men eftersom du talat om för kompilatorn att AB är trunkerat till uint8_t så har du gett den frihet att agera utifrån det.
Heja stekern! det där hade jag inte koll på, men det förklarar ju ett och annat. Tack för att du tar dig tid!
Ja, helt enkelt är det iaf inte att skriva C-kod som kompilerar till det som man tänkt sig alla gånger.
Jag har egentligen mest haft problem av den här typen på plattformar med extra stor ackumulator och MAC-instruktioner (multiply-accumulate), där man gärna vill behålla alla delresultaten i ackumulatorn för att undvika rundningar.
Whohooo! Den förbättrade algoritmen drog ned tiden från 2,4 ms till 0,9 ms. Verkligen inte illa pinkat! I båda tiderna ingår lite annat enkel dataskyfflande som måste göras, så om vi gissar att interpolerandet gått från ca 2 till 0,5 ms ... 4 ggr snabbare!
Det är 16 RGB-dioders färg som ska beräknas. 48 interpoleringar totalt. Dvs storleksordningen 10 mikrosekunder per interpolering. Helt OK siffror, tycker jag.
EDIT: 10, inte 100
Senast redigerad av Wedge 25 oktober 2012, 23:23:02, redigerad totalt 1 gång.
superx skrev:Jag har egentligen mest haft problem av den här typen på plattformar med extra stor ackumulator och MAC-instruktioner (multiply-accumulate), där man gärna vill behålla alla delresultaten i ackumulatorn för att undvika rundningar.
Just DSP operationer har väl traditionellt varit lämnat åt att skrivas i assembler,
så att man får jobba lite extra för att få kompilatorerna att förstå vad man vill där kan jag mycket väl tänka mig.
Det blir säkert bättre på den fronten framöver, det samma gäller även vector instruktioner.
M är variabel, ja. Den bestämmer hur lång en övergång från en färg till en annan ska vara. Sen räknar x ned från M till 0, ett steg för varje interrupt.