0

Refering Notation for fixed point representation i have tried following, but i am totally confused.

int q = 1<<15;
printf("(sys3.b0 * q) = %hx \n",((0.2929 * q)));

output is

((0.2929 * q)) = cc60

I expect to see 257d because from calculator, 0.2929 * 32768 in hex = 257d

What is the problem in using this Q.15 format, or is this just because of not properly printing


EDIT

Guys, actually i've never thought of it.

My actual code tries to print two values. I thought 2nd value printing is the problem. After comments of @Soren i copied his code and is working. Then i removed 1st value from printf, my code also worked. So i repost the printf statement

printf("(sys3.b0 * q) = %X \t((0.2929 * q)) = %X\n",(sys3.b0 * q),(unsigned)((0.2929 * q)));
printf("(sys3.b0 * q) = %X \n",((unsigned)(0.2929 * q)));

where the second line is as suggested by Seron.

The value of sys3.b0 = 0.0000000001295

Now the output is

(sys3.b0 * q) = 4DB173CF        ((0.2929 * q)) = 3ED1CC60
(sys3.b0 * q) = 257D
Community
  • 1
  • 1
nmxprime
  • 1,506
  • 3
  • 25
  • 52

2 Answers2

1

What you have is undefined behavior the result of:

0.2929 * q

is a double but you are telling printf it is a unsigned short. If you cast the result to unsigned short you will get the result you expect (see it live):

printf("(sys3.b0 * q) = %hx \n",(unsigned short)(0.2929 * q));
                                ^^^^^^^^^^^^^^^^

Having warning turned on or up should have indicated that this was a problem, both gcc and clang give similar errros:

warning: format '%hx' expects argument of type 'int', but argument 2 has type 'double' [-Wformat=]

Although apparently Visual Studio does not.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • i m in MS VC++ environment, and all warnings are up. typecasting still results same output – nmxprime Mar 21 '14 at 13:32
  • @nmxprime I added a live example with this code working correctly in visual studio. – Shafik Yaghmour Mar 21 '14 at 13:34
  • @nmxprime still undefined behavior change `(sys3.b0 * q)` to `(unsigned)(sys3.b0 * q)` – Shafik Yaghmour Mar 21 '14 at 14:23
  • Thanks! Fine, but anuy hint on this unusual behaviour? might be windows's way of doing? Now i dnt have linux pc to test it with gcc – nmxprime Mar 21 '14 at 14:34
  • 1
    @nmxprime you can use both `gcc` and `clang` through one of the many [online compilers](http://stackoverflow.com/questions/3916000/online-c-compiler-and-evaluator) available. Undefined behavior means that the behavior is unpredictable when you specify `%X` but pass in a `double` most likely printf is taking garbage values from the stack or maybe registers since `double` will usually be larger than `unsigned`. – Shafik Yaghmour Mar 21 '14 at 14:36
  • Thanks a lot!! Accepting your answer so that this thread may closed!! – nmxprime Mar 21 '14 at 14:40
0

The format string expects a type different from the one you're actually giving it. My compiler says:

foo.c:5:33: warning: format specifies type 'unsigned short' but the argument has type 'double' [-Wformat]

So you need a cast to convert 0.2929 * q from a double to an unsigned int. Like this:

int main() {
    int q = 1<<15;
    printf("(sys3.b0 * q) = %X \n",((unsigned)(0.2929 * q)));
}

EDIT: When you feed printf an argument of the wrong type, it'll read only as many bytes as the type it thought it was getting. In your case:

printf("(sys3.b0 * q) = %X \t((0.2929 * q)) = %X\n",
       (sys3.b0 * q),
       (unsigned)((0.2929 * q)))

The format string says to expect two unsigned int, that is, two times 4 bytes*. But you gave it a double and an unsigned int, which are respectively 8 and 4 bytes*. printf just reads 4 bytes for each %X, so effectively it reads the 8-result of sys3.b0 * q, thinking those 8 bytes are two integers, which it then prints.

Søren Debois
  • 5,598
  • 26
  • 48