Can this Code be More Efficient?

Hi All.

So, I have 18-bit two's complement sample data stored (sign extended) in 32-bit integers. I need to scale these numbers to fit into 16-bit integers. The obvious choice is to shift right two places. But, I want to use the two lower-order bits to round the result rather than just throwing them away. I also want the rounding to be "symmetric" for both positive and negative quotients. Meaning and answer of 8.5 would round to 9 and an answer of -8.5 would round to -9.

The code below works, but strikes me as inelegant and perhaps inefficient. Would like to hear suggestions for improving it.

Thanks.

Code:

void setup() {  
  int32_t sampleData[] = {37259, 37258, 37257, 37256, -37259, -37258, -37257, -37256};
  int32_t sample;
  int16_t scaled;
  uint8_t index, bit1;
  float floating;
  const uint8_t sampleSize = sizeof(sampleData) / sizeof(int32_t);

  Serial.println(115200);
  delay(1000);

  Serial.println("Division    Floating      Rounded");
  for (index=0; index<sampleSize; index++) {
    sample = sampleData[index];
    floating = sample / 4.0;
    Serial.print(sample); Serial.print(" / 4    "); Serial.print(floating); Serial.print("        ");
    
//----------- Can this code be more efficient? ------------    
    if (sample >=0) {
      sample >>= 1;
      bit1 = sample & 0b1;
      sample >>= 1;
      scaled = sample + bit1;
    } else {
      sample = -sample;
      sample >>= 1;
      bit1 = sample & 0b1;
      sample >>= 1;
      scaled = -(sample + bit1);      
    }
//--------------------------------------------------------

    Serial.println(scaled);    
  }
}

void loop() {
}

Result:

Division    Floating      Rounded
37259 / 4    9314.75        9315
37258 / 4    9314.50        9315
37257 / 4    9314.25        9314
37256 / 4    9314.00        9314
-37259 / 4    -9314.75        -9315
-37258 / 4    -9314.50        -9315
-37257 / 4    -9314.25        -9314
-37256 / 4    -9314.00        -9314

There is a round() function that might do what you want.

I find it disconcerting to see a column heading, Rounded, when the value in that column was a result of printing a variable called scaled.

What about these steps

  • record the sign of the value
  • get the abs() of the value
  • save the two low bits into another variable by masking off all the higher bits
  • shift the value two places right
  • add 1 to the value depending on the amount in the two low bits.
  • replace the sign of the value

...R

Robin2:
What about these steps

  • record the sign of the value
  • get the abs() of the value
  • save the two low bits into another variable by masking off all the higher bits
  • shift the value two places right
  • add 1 to the value depending on the amount in the two low bits.
  • replace the sign of the value

...R

That's essentially what the code I posted does. I have and idea for another implementation, but won't have access to actual hardware to test it for 9 hours or so.

To round off the result from division of positive integers, most people just do the following:

int y = (x + divisor/2)/divisor;

Here's the best I've come up with so far. To relieve PaulS's distress, I renamed the column heading and variables so the match each other.

void setup() {  
  int32_t sampleData[] = {37259, 37258, 37257, 37256, -37259, -37258, -37257, -37256};
  int32_t sample;
  int16_t scaledRounded;
  uint8_t index;;
  float floating;
  const uint8_t sampleSize = sizeof(sampleData) / sizeof(int32_t);

  Serial.println(115200);
  delay(1000);

  Serial.println("Division    floating      scaledRounded");
  for (index=0; index<sampleSize; index++) {
    sample = sampleData[index];
    floating = sample / 4.0;
    Serial.print(sample); Serial.print(" / 4    "); Serial.print(floating); Serial.print("        ");
    
//----------- Can this code be more efficient? ------------    
    if (sample >=0) {
      scaledRounded = (sample + 0b10) >> 2;
    } else {
      scaledRounded = -((-sample + 0b10) >> 2);  
    }
//--------------------------------------------------------

    Serial.println(scaledRounded);    
  }
}

void loop() {
}
Division    floating      scaledRounded
37259 / 4    9314.75        9315
37258 / 4    9314.50        9315
37257 / 4    9314.25        9314
37256 / 4    9314.00        9314
-37259 / 4    -9314.75        -9315
-37258 / 4    -9314.50        -9315
-37257 / 4    -9314.25        -9314
-37256 / 4    -9314.00        -9314

This looks neat

scaledRounded = (sample + 0b10) >> 2;

...R