## C multiplication syntax

12 posts / 0 new
Author
Message

Hi guys,

I'm building a soft audio volume control. What is the best C syntax to use UC3A3 hardware in a fast and convenient way?

Basically, I'm doing A = A * V/C + D, where:

A = signed 32-bit audio sample where upper 24 bits are sent to DAC chip

V = volume variable, 16 or 32-bit signed or unsigned

C = scaling constant so that max(V/C) = 1

D = random dither applied in lower 8 bits of A prior to truncating

Cheers,

Børge

It should not make any difference what your target is.

```// if C is an integer
A = (A * V) / C + D;    // make sure that the intermediate (A * V) fits in int32_t
// if C is f-p
A = A * (V / C) + D;    // this is fine if C is a floating point constant or variable
```

The execution time will be trivial for either approach.   The second avoids overflow / underflow issues.

Since you will be using native int32_t variables,   overflow is less likely than a 16-bit AVR program.

David.

borge.strand wrote:
Basically, I'm doing A = A * V/C + D, where:

Can we assume you wrote that with BODMAS and left-to-right operation in mind? That is:

A = ((A * V)/C) + D

Or was the intention:

A = (A * (V/C)) + D

If the latter is the V/C some ratio that could be precalculated just once then applied to multiple invocations of * A ?

I believe I'd like to go the way through a 64-bit signed temp. That way I don't loose precision in V (which can be forgiven) or A (which may not happen)

The mul instruction is 32<-32x32 while muls.d is 64<-32x32. I could code this up in asm with muls.d and then an asr on the result for the division by C. Knowing the range of the variables the result then ends up in the lower 32 bits of the 64-bit temp.

I'm working on a 64-bit asr now and plan to merge that with a muls.d. I just can't provoke the compiler to produce any muls.d.

Børge

S64 mmuulltt(S64 A) {

return A >> 28;

// Compiles into this. I've verified the shifts in Excel

//    lsr     r10, 28
//    or        r10, r10, r11 << 4
//    asr     r11, 28

}

borge.strand wrote:
. I could code this up in asm

Why when the C compiler is perfectly able to do this for you?

If you want to say to C "I'd like this done with this precision" then just typecast up one of the inputs to your desired width. So if you have:

`uint32_t a,b,c;`

and want:

`c = (a * b) / 100000;`

(say) but worry that the (a * b) might spill beyond 32 bits then use something like:

`c = ((uint64_t)a * b) / 100000;`

and the cast there will take the whole thing up to 64 bits.

Perhaps it's just me not understanding the asm that comes out of the compiler.

```int64_t mmuulltt(int32_t A, int32_t V) {
return ( (int64_t)(A * V) >> 28);
}```

compiles into

```mul     r11, r12        #  tmp26, A
asr     r10, r11, 28    #  tmp4, tmp26,
asr     r11, 31         # ,
retal   r12```

Given the definition of mul in doc32000.pdf as 32<-32x32 I don't see clearly how (int64_t)(A * V) is executed with full precision.

Børge

Because you have cast the result and not the individual operand.
Put the parentheses in the right place.

OK! I was able to get what I wanted with

```int32_t Cmult(int32_t A, int32_t V) {
int64_t X = (int64_t)( (int64_t)A * (int64_t)V ) >> 28;
return ( (int32_t)(X >> 0) );
}
```

Essentially, it multiplies A and V, does a serious right-shift and outputs the lower 32-bit word. This time it generates code with muls.d.

The asm generated by the C code and what I optimized by hand converged nicely. I'm forever impressed with the capabilities of the compilers!

My coding carreer started with asm, and to date I mentally use C as a collection of asm macros :-)

Børge