don't click here

Writing portable C

Discussion in 'Technical Discussion' started by BenoitRen, Mar 1, 2024.

  1. BenoitRen

    BenoitRen

    Tech Member
    770
    379
    63
    Thanks for the suggestion. As the entire point (hah) of fixed point integers is to not use floats, I'm hesitating to use that solution. But I may have to in the future.
     
  2. DigitalDuck

    DigitalDuck

    Arriving four years late. Member
    5,403
    487
    63
    Lincs, UK
    TurBoa, S1RL
    A division that truncates rather than floors an int is going to be doing some processing of the inputs before performing the division anyway, that's unavoidable when you need to treat a signed number differently to an unsigned number (which isn't the case for addition, subtraction, or multiplication).

    Naturally you could check the modulus and subtract one specifically only if it's negative and not divisible by 65536: x / 65536 - (x % 65536 < 0 ? 1 : 0)
     
  3. Clownacy

    Clownacy

    Tech Member
    1,093
    666
    93
    Code (C):
    1. #define DISCARD_LOWER_BITS(bits, x) (((x) - (((1 << bits) - 1) * ((x) < 0))) / (1 << bits))
    2. #define DISCARD_LOWER_16_BITS(x) DISCARD_LOWER_BITS(16, x)
    This should work.
     
  4. BenoitRen

    BenoitRen

    Tech Member
    770
    379
    63
    My apologies; I should have mentioned that I had cooked something up this morning, which happens to be exactly what DigitalDuck just suggested:
    Code (C):
    1. short util__longhigh_to_short(long value) {
    2.   bool negative = value < 0;
    3.   short result = value / 65536;
    4.   if (negative && value % 65536 != 0) {
    5.     --result;
    6.   }
    7.  
    8.   return result;
    9. }
    That being said, that's a cool macro, Clownacy. You subtract the divisor from the dividend before division if it's negative to ensure the end result is lower by 1. And it seems to also work when the entire number is divisible by the original divisor by subtracting 1 from the divisor used in the first part.
     
    Last edited: Sep 5, 2024
  5. ndiddy

    ndiddy

    Member
    23
    6
    3
    Not my project so I don't want to tell you what to do, but here's an example of the performance and code clarity you're sacrificing by not assuming two's complement integers. The first two solutions are the two above this post, while I did the last solution assuming two's complement. You're making your code far more complex to gain compatibility with a few obscure mainframe systems, none of which can even output color graphics.
     
    Last edited: Sep 7, 2024
  6. Clownacy

    Clownacy

    Tech Member
    1,093
    666
    93
    Code (C):
    1. short longhigh_to_short(long value) {
    2.     unsigned long value_unsigned = (unsigned long)value;
    3.     long value_shifted = (long)(value_unsigned >> 16);
    4.     return (value_shifted & 0x7FFF) - (value_shifted & 0x8000);
    5. }
    Here's a version that doesn't rely on C99 fixed-width integers.
     
  7. BenoitRen

    BenoitRen

    Tech Member
    770
    379
    63
    I'm not seeing the point on code clarity. The code resides in a clearly-named function.

    Assembly-wise, it is more complex, no question about that. But unless it's a performance-sensitive part of the code, I don't think it matters.

    It's not about compatibility with obscure mainframe systems. It's about avoiding implementation-defined behaviour.
     
    Last edited: Sep 7, 2024