1

I have access to an instrument that runs a C-style scripting language on it. It can declare and use variables or arrays of char, int and double but not float. It allows the operands of standard C logic and addition, subtraction, division and multiplication. It doesn't have useful functions such as sizeof() and doesn't have any of the bit shift operators <<, >>.

I am trying to get it to send a double value over two binary output ports. Each can be set High or low.

I was thinking that I should do this by bit-shift masking the double value using the bit-wise AND comparator. However I CAN'T do this because bit shift operators don't exist. I would then use one output port as a clock and the second as the synced data line.

For example using an input byte with value = 6 (0000 0110). The data would be output like below with X denoting the read value on the 'clock' down stroke:

*Clock,  Input
* 0,     0
* 1,     0 X
* 0,     0
* 1,     1 X
* 0,     0
* 1,     1 X
* 0,     0
* 1,     0 X
* 0,     0
* 1,     0 X
* 0,     0
* 1,     0 X
* 0,     0
* 1,     0 X
* 0,     0
* 1,     0 X
* 0,     0

So I need a way of iterating through the double bit-by-bit (not sure how many bits the instrument uses for its double) and setting the output flag to its value but this can't be done with bit-shift because I don't have it.

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • 4
    Remember that shifting a value one bit left is the same as multiplying with 2. – Some programmer dude Mar 11 '14 at 15:15
  • Sending a `double` in binary is not the best idea in the world. Does the variable have to be `double`? Could you do away with converting it to a couple of integers (e.g. integer part and fraction part) etc? – Shahbaz Mar 11 '14 at 15:16
  • I could turn the double into a 0.000 (5 char) c-string array I guess and attempt to transmit it if that would make it easier ? – user3406725 Mar 11 '14 at 16:13
  • note that [`sizeof` is not a function](https://stackoverflow.com/q/1393582/995714) because you can use `sizeof var` without parentheses, and functions can't receive a type as parameter – phuclv Jul 21 '18 at 06:25

4 Answers4

1

Shifting a value is equivalente to multiply/divide by two (using integer math):

 a / 2   equivalent to  a >> 1 
 a * 2   equivalent to  a << 1 

You need to check that the scripting language do integer math (or use the floor() or int() or trunc() or wathever the language offers).

Be also careful with overflow, if the scripting language uses float instead of ints to represent numbers, you may expect strange behaviour with big numbers.

Another caveat on signedness. If you have to deal with negative numbers, shifting to left is more complicated.

Can you run a couple of tests to check the size of integer numbers? It will surely help you avoid problems.

Remo.D
  • 16,122
  • 6
  • 43
  • 74
0

A left shift 1 is equal to a multiply by 2, a right shift 1 is equal to (integer) division by 2. So, a left shift of 3 is equal to multiplication by 8 (because it is 23).

#include <stdio.h>

int main() {
  int a = 17 << 4;
  int b = 17 * 16;

  if (a == b) {
    printf("%i\n", b);
  } else {
    puts("false");
  }
}

Output is

272
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
0

Assuming the measurements you are trying to retrieve are truly doubles: If you know the allowable range of the measurement, I would multiply them by a factor of 0xFFFFFFFF/MAX_RANGE factor to give you a value between 0 and int max.

Then you can do

long int value = double*FACTOR;
for (i=0;i<32;i++) {
    long int nextval = value / 2;
    char bit = value - (nextval * 2);
    //send bit here
    value = nextval;
 }

This will be better than trying to work with the bitwise representation of floats without masks and shifting.

AShelly
  • 34,686
  • 15
  • 91
  • 152
0

Bit shifts are just like multiplication or division, so the simplest solution to shift left/right N bits is just multiply/divide by 2N

const unsigned int SHIFT_BY[] = { 1U, 2U, 4U, 8U, 16U, 32U, 64U, 128U, 256U, 512U,
    1024U, 2048U, 4096U, 8192U, 16384U, 32768U, 65536U, 131072U, 262144U, 524288U,
    1048576U, 2097152U, 4194304U, 8388608U, 16777216U, 33554432U, 67108864U,
    134217728U, 268435456U, 536870912U, 1073741824U, 2147483648U};

unsigned int lshift(unsigned int x, unsigned int numshift)
{
    return x*SHIFT_BY[numshift];
}
unsigned int rshift(unsigned int x, unsigned int numshift)
{
    return x/SHIFT_BY[numshift];
}

But that won't be efficient for small shift steps or on architectures without division/multiplication. In that case just add the number to itself since it's equivalent to multiplying it by 2 which may improve performance a bit

unsigned int lshift(unsigned int x, unsigned int numshift)
{
    for (i = 0; i < numshift; i++)
        x += x;
    return x;
}

Right shift is a lot trickier to implement with only addition/subtraction. If you don't want to use the slow division then you can use a lookup table

unsigned int rshift1(unsigned int x)
{
    const unsigned int RSHIFT1[] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
    assert(x < 16);
    retrn RSHIFT1[x];
}

Above is just a simple 4-bit LUT to shift by 1. You can use a bigger LUT if you want/can. You can also implement shifting by more than 1 as a 2D array, or by shifting by 1 multiple times. This method can also be applied to left shift

phuclv
  • 37,963
  • 15
  • 156
  • 475