views:

62

answers:

2

Hi

I need to convert from fixed point signed Q8 format to fixed point signed Q4 format in c. I assume that I can just do a bitshift by four, is this correct? Do I need to take into account the sign bit?

Update: This is for an ARM11 architecture, but I would prefer a non-architecture specific solution.

Thanks

+1  A: 

A bitshift should work and will also take care of the sign bit on many architectures. In case of negative numbers, more ones will be shifted in but you will either only use the lower 5 Bits or do arithmetic in C where you need these additional ones to form the correct twos complement.

Assuming ints, the code would simply be:

int q4 = q8 >> 4;

Perhaps you would like to round:

int ahalf = q8 >= 0 ? (1<<3) : (1<<3)-1;
int q4 = (q8+ahalf) >> 4;

Ok, I listen to Oli and present a solution for architectures that do not shift sign-correct:

int q4 = q8 / (1<<4);

The optimizer should convert the division to a shift if possible.

With rounding, a first solution is

int ahalf = q8 >= 0 ? (1<<3) : -(1<<3);
int q4 = (q8+ahalf) / (1<<4);

Thanks to R..'s persistence I finally tested all versions and they now produce the correct results with Intel 32 Bit signed integers under Linux.

Peter G.
The result is implementation-defined for negative numbers. In practice on a two's-complement machine, sign bits will be shifted in. But you can't guarantee that in general.
Oli Charlesworth
Yes, that's why I added "on many architectures" ;-). I defer taking care of the exception to when the OP reports his architecture doesn't shift in ones from the MSB.
Peter G.
The division produces different results. Whereas `>>` will round down ("towards negative infinity") if it works, the division will round towards zero. Your adding of `(1<<3)` probably makes no sense with division.
R..
@R.. thanks, corrected
Peter G.
The non-rounded versions with shift versus division still have different behavior.
R..
@R.. Fixed that. My goal however was sensible rounding and not guaranteeing 100% equal behaviour in all versions.
Peter G.
I don't see it. `q8>>4` and `q8/(1<<4)` definitely have different behavior when `q8` is negative. I don't think you need to "fix" it, but I think it merits mention in the answer rather than presenting them as equivalents.
R..
Just to be sure, will the `int q4 = q8 (1<<4)` work both on architectures that do shift in ones _and_ on architectures that do not? Or will my solution have to be architecture specific?
bjarkef
@bjarkef Only the dividing solutions are architecture independent.
Peter G.
A: 

I know C`s right shift behaviour is implementation defined. See 6.5.7/5 of the Standard

(some computers might copy the MSB as in the image below; others might add a '0')

It doesn't look like a lot of work to care about the sign bit.

But if your code is going to be compiled only on the same machine, you can check that machine implementation and ignore the sign bit if it "works"

pmg