tags:

views:

79

answers:

4

Hello,

Consider the following C code:

  int c=((0xa3>>6)&0x1f)|0xc0;
  printf("%d\n",c);

It correctly prints out 194 (0xc2). If I write the same thing in wcalc, the result is 195, or 0xc3. Is this some sort of precision error? Is this expected behavior? floor and ceiling functions do not work... or, to be more specific, floor works for 0xa3, but not for, say 0xa1, and vice versa.

Any help appreciated. Thanks.

+1  A: 

This is an integer operation, there are no floating point precision issues involved. The correct answer is exact, and as you already know is being reported correctly by the example code. It sounds like a bug in "wcalc" (a tool I don't know) to me.

Andy Ross
Or, wcalc has a model that interprets '0xA3 >> 6' as '0xA3 / 64.0' and then goes on from there. It may be using the wrong tool for the job, rather than a bug in wcalc per se.
Jonathan Leffler
+3  A: 

Why are you asking instead of testing? Break it down. What do you get from the following?

0xa3>>6
(0xa3>>6)&0x1f
((0xa3>>6)&0x1f)|0xc0

Enter an expression to evaluate, q to quit, or ? for help:
-> ((0xa3>>6)&0x1f)|0xc0
 = 195
-> 0xa3>>6
 = 2.54688
-> (0xa3>>6)&0x1f
 = 3
-> ((0xa3>>6)&0x1f)|0xc0
 = 195
->

See that line "= 2.54688". Does that look right to you? By my calculations, 0xa3>>6 should give you 2 which, when anded with 0x1f, would still be 2.

If you try out the following, you'll see that >> is not giving integer results:

Enter an expression to evaluate, q to quit, or ? for help:
-> 0xa3
 = 163
-> 0xa3>>1
 = 81.5
-> 0xa3>>2
 = 40.75
->
paxdiablo
For what it's worth, wcalc 2.4 seems to do it 'correctly' - without the conversion to float and rounding.
Matt B.
Relax. I'd done the tests, and yes, I saw the decimal, but did not think it had a baring on the results, since they were all ints. My bad.
Dervin Thunk
I expected the 'correctly' that Matt is talking about, even if I got the decimal in one of the steps... you wouldn't have?
Dervin Thunk
No, I wouldn't have. The minute I saw a float I would have been suspicious. And the next step would have confirmed it (the one where it rounds 2.54688 to 3 when anding with 0x1f). That's why I said to break it down and gave you the walkthrough.
paxdiablo
+2  A: 

In effect, wcalc treats x >> y not as an integer bitshift operator (which simply drops shifted bits off the right hand side) but as floating-point division of x by 2^y. Hence:

Enter an expression to evaluate, q to quit, or ? for help:
-> 0xa3>>6
 = 2.54688

And this explains the difference relative to the C version, where 0xa3 >> 6 is simply 2.

Martin B
+2  A: 

I'm the author of wcalc; you must be using version 2.3.1 (which is almost a year out of date).

The cause of what you're seeing is that wcalc uses arbitrary-precision floating point numbers internally, from the mpfr library, and because of that, used to perform shifts as a division (and can thus handle things like 1.5>>6). Version 2.4 (which came out in October 2008) handles integer bit-shifts slightly differently, to produce C-like results (as you expect).

For what it's worth, an alternative command line calculator is bc (older, but more of a pain to use, and without as many features, in my not-unbiased opinion).

Kyle Wheeler
Thanks, Kyle. Just apt-get installed it, so I will make sure I upgrade it asap. Great tool, though, and I'm happy I can 'fix' it to go on using it.
Dervin Thunk