My problem is that I have a mic that delivers 24 bits 2's complement signed. There is nothing in that data sheet that hints at it not also delivering INT_MIN. The 8 LSB bits are zero and INT_MIN is 0x80000000. I have myself written the driver, which takes in bits for stereo (needed even if I only use one mic) at an SCK rate of exactly 1024 kHz for 16 kHz samples. Only one of the stereo channels are valid.

INT_MIN could potentially be a problem. I am making a mask of abs of all the signed values, for a 32 ms window and not sending those into the FFT etc. That mask would then get NumLeadingZeros completely wrong if INT_MIN is only one sample. The AGC (before the FFT) would fail miserably.

From the fist version of this question (which was about to be shipped to Stack Overflow) I was advised that "it's almost always better to insure that x = - INT_MIN equals INT_MAX". So I assume that this probably is about as good answer as I could expect.

  1. Instead of doing the absx as described below I have now made a function that does exactly what suggested above
  2. When it comes to the FFT, I don't know if INT_MIN would be a problem. I could analyse the source, but it's a library in assembly code. I haven't tested INT_MIN, since analysing the result would be difficult for me. On a general basis, standard FFT (with int32_t input), might INT_MIN be a problem?

I'll keep the original text below, even if it may misled the reader to think that I was concerned with the abs vs. absx. Partly because many of the responses relate to it.

--- From original posting:

In Why the absolute value of the max negative integer -2147483648 is still -2147483648? we see that since 2's complement is not symmetrical (it can't be, because zero also needs a space) I have come to not "believe" in my old abs macro (C). The problem is INT_MIN, which is on a one value "longer" negative "ruler" than the positive "ruler", which ends at "one shorter" value INT_MAX.

So abs(INT_MIN) strictly is not defined.

Per def abs(any_signed_value) should yield a positive value in my head. The math after this could really misbehave if not so. My standard macro does not deliver as I want to:

#define abs(a) (((a)<0)?(-(a)):(a))

But this one takes the last value that it's possible to invert when it sees INT_MIN, namely INT_MAX:

#define absx(a) ((a)==(INT_MIN)?(INT_MAX):((a)<0)?(-(a)):(a))

Testing with this code (xC on XMOS X2 core) I get:

#include <limits.h>
void test_abs (void) {  
    signed int_min    = INT_MIN;
    signed int_min_p1 = INT_MIN + 1;

    debug_print ("abs(int_min)\t%d - abs(int_min_p1)\t%d\n",    abs(int_min),  abs(int_min_p1));
    debug_print ("absx(int_min)\t%d - absx(int_min_p1)\t%d\n", absx(int_min), absx(int_min_p1));

    // abs(int_min) -2147483648 - abs(int_min_p1)  2147483647
    // absx(int_min) 2147483647 - absx(int_min_p1) 2147483647

    signed int_zero = 0;
    signed int_pos  = 1;

    debug_print ("abs(int_zero)\t%d - abs(int_pos)\t%d\n",    abs(int_zero),  abs(int_pos));
    debug_print ("absx(int_zero)\t%d - absx(int_pos)\t%d\n", absx(int_zero), absx(int_pos));

    // abs(int_zero)  0 - abs(int_pos)  1
    // absx(int_zero) 0 - absx(int_pos) 1

I don't want an assert for the INT_MIN case, I instead want to keep on running.

Would anybody see some side effect of this that I don't see? Wikipedia Absolute value doesn't make it simpler, does it.

  • 1
    $\begingroup$ While this question has bearing on signal processing (for a given variable x it's almost always better to insure that x = - INT_MIN equals INT_MAX), it's really a question about C and the C standard. There's already a lot of material about this on StackOverflow, and if you ask 'why' the conversation quickly gets into the minutia of the C standard -- which is outside the purview of this group. $\endgroup$
    – TimWescott
    Jan 27 at 16:20
  • 1
    $\begingroup$ If I was to give a general recommendation about writing C for DSP, it would be that macros are basically never a good idea. You want to have a function $f(x) = \lvert y\rvert$, so write a function int abs(int value);; for good measure, you can slap an inline in front of that, but you win absolutely nothing by writing this as a macro, unless your compiler is older than it should be or running with any kind of code restructuring disabled (and then you wouldn't want a macro, either). You can also simply use your compiler to verify a function is correct: enable optimizations, and just $\endgroup$ Jan 27 at 16:57
  • 1
    $\begingroup$ loop over the whole integer range! Look at gcc.godbolt.org/z/3MKMbojvc : my inline int abs(int) gets completely compiled away, because it's never different from the correct value, so the assert never triggers, so there's not actually any code to execute. The compiler knows this, because it does understand that abs(int value) does in fact compute value for value >=0 and -value for anything else but INT_MIN. Easy-peasy for the code analyzer to just erase a -value == -value check, and even easier for it to remove value == value. You really win nothing with macros! $\endgroup$ Jan 27 at 16:59
  • $\begingroup$ Thanks! I never really found out what to use where. I used an inline function the other day for wrapping around an asm. I see that the lib_dsp and others would use macros (in C) a lot, like for "Convert from floating point to fixed point Q format like #define Q31(f) (int)((signed long long)((f) * ((unsigned long long)1 << (31+20)) + (1<<19)) >> 20)". But I take your point. But from my test code it looks like the compiler (llvm based, 2019 ca: xccllvm) does val=(-INT_MIN) as no change, which is "legal" from the standard it looks like, (..) $\endgroup$ Jan 27 at 17:49
  • $\begingroup$ (..) but I'll have to interfere. I'll keep that in mind and try to move away from macros! I also take the point to clean my dataset from INT_MIN initially to avoid this specialised absx. I also read that doing what I suggest is "ok enough". Thanks! $\endgroup$ Jan 27 at 17:49


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.