abs and round macros

Status
Not open for further replies.

Frank B

Senior Member
Teensyduino still uses these Arduino macors for abs and round
Code:
#define abs(x) ({ \
  typeof(x) _x = (x); \
  (_x > 0) ? _x : -_x; \
})
#define round(x) ({ \
  typeof(x) _x = (x); \
  (_x>=0) ? (long)(_x+0.5) : (long)(_x-0.5); \
})

Not only that round causes warnings for double promotions... , they are not needed because they are already exist in newlib , are builtins for gcc, etc.
So, anyone knows why we need these macros, and would it be a problem to remove them?

Edit: Yes, one can argue that this round returns a long. Ok, if Arduino really wants that (why?? - its against the standards) you could better write that as #define round(x) ((long)__builtin_round(x)) - so why that macro with a conditional, and doubles?
 
Last edited:
so... lets see what goldbolt says: https://godbolt.org/z/o93eGadd9

Code:
[COLOR=#000000][FONT=Consolas]
[COLOR=#0000ff] #define[/COLOR][COLOR=#000000] roundx(x) (([/COLOR][COLOR=#0000ff]long[/COLOR][COLOR=#000000]) __builtin_round(x))[/COLOR]


[COLOR=#0000ff]long[/COLOR][COLOR=#000000] f([/COLOR][COLOR=#0000ff]float[/COLOR][COLOR=#000000] x) {[/COLOR]
[COLOR=#0000ff]return[/COLOR][COLOR=#000000] roundx([/COLOR][COLOR=#000000] x);[/COLOR]
[COLOR=#000000]}[/COLOR]

[COLOR=#0000ff]#define[/COLOR][COLOR=#000000] round(x) ({ \[/COLOR]
[COLOR=#000000]  typeof(x) _x = (x); \[/COLOR]
[COLOR=#000000]  (_x>=[/COLOR][COLOR=#098658]0[/COLOR][COLOR=#000000]) ? ([/COLOR][COLOR=#0000ff]long[/COLOR][COLOR=#000000])(_x+[/COLOR][COLOR=#098658]0.5[/COLOR][COLOR=#000000]) : ([/COLOR][COLOR=#0000ff]long[/COLOR][COLOR=#000000])(_x-[/COLOR][COLOR=#098658]0.5[/COLOR][COLOR=#000000]); \[/COLOR]
[COLOR=#000000]})[/COLOR]

[COLOR=#0000ff]long[/COLOR][COLOR=#000000] f1([/COLOR][COLOR=#0000ff]float[/COLOR][COLOR=#000000] x) {[/COLOR]
[COLOR=#0000ff]return[/COLOR][COLOR=#000000] round(x);[/COLOR]
[COLOR=#000000]}[/COLOR]
[/FONT][/COLOR]




Code:
[COLOR=#000000][FONT=Consolas][COLOR=#008080]f(float):[/COLOR]
[COLOR=#0000ff]vcvt.f64.f32[/COLOR][COLOR=#008080]d0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]s0[/COLOR]
[COLOR=#0000ff]vrinta.f64[/COLOR][COLOR=#008080]d0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]d0[/COLOR]
[COLOR=#0000ff]vcvt.s32.f64[/COLOR][COLOR=#008080]s15[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]d0[/COLOR]
[COLOR=#0000ff]vmov[/COLOR][COLOR=#4864aa]r0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]s15[/COLOR][COLOR=#008080]@[/COLOR][COLOR=#008080]int[/COLOR]
[COLOR=#0000ff]bx[/COLOR][COLOR=#4864aa]lr

[/COLOR]
[COLOR=#008080]f1(float):[/COLOR]
[COLOR=#0000ff]vcmpe.f32[/COLOR][COLOR=#008080]s0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#098658]#0[/COLOR]
[COLOR=#0000ff]vmov.f64[/COLOR][COLOR=#008080]d7[/COLOR][COLOR=#000000], [/COLOR][COLOR=#098658]#5.0e-1[/COLOR]
[COLOR=#0000ff]vcvt.f64.f32[/COLOR][COLOR=#008080]d0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]s0[/COLOR]
[COLOR=#0000ff]vmrs[/COLOR][COLOR=#008080]APSR_nzcv[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]FPSCR[/COLOR]

[COLOR=#0000ff]ite[/COLOR][COLOR=#008080]ge[/COLOR]

[COLOR=#0000ff]vaddge.f64[/COLOR][COLOR=#008080]d0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]d0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]d7[/COLOR]
[COLOR=#0000ff]vsublt.f64[/COLOR][COLOR=#008080]d0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]d0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]d7[/COLOR]
[COLOR=#0000ff]vcvt.s32.f64[/COLOR][COLOR=#008080]s0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]d0[/COLOR]
[COLOR=#0000ff]vmov[/COLOR][COLOR=#4864aa]r0[/COLOR][COLOR=#000000], [/COLOR][COLOR=#008080]s0[/COLOR][COLOR=#008080]@[/COLOR][COLOR=#008080]int[/COLOR]
[COLOR=#0000ff]bx[/COLOR][COLOR=#4864aa]lr
[/COLOR][/FONT][/COLOR]




The macro version without builtin is way longer and takes 2x the time.
But , still, any reason why it must return long, and why that abs macro?
 
Last edited:
Does anything speak against using the standard one from math.h? (GodBolt https://godbolt.org/z/fT51Modc6)

Code:
#include <cmath>
 
#define roundx(x) ((long) __builtin_round(x))

#define round_macro(x) ({ \
  typeof(x) _x = (x); \
  (_x>=0) ? (long)(_x+0.5) : (long)(_x-0.5); \
})

long useMacro(float x) {
    return round_macro(x);
}

long useBuiltIn(float x) {
    return roundx(x);
}

long useStandard(float x) {
    return roundf(x);  // from math.h
}

Gives:
Code:
useMacro(float):
        vcmpe.f32       s0, #0
        vmov.f64        d7, #5.0e-1
        vcvt.f64.f32    d0, s0
        vmrs    APSR_nzcv, FPSCR
        ite     ge
        vaddge.f64      d0, d0, d7
        vsublt.f64      d0, d0, d7
        vcvt.s32.f64    s0, d0
        vmov    r0, s0  @ int
        bx      lr
useBuiltIn(float):
        vcvt.f64.f32    d0, s0
        vrinta.f64      d0, d0
        vcvt.s32.f64    s15, d0
        vmov    r0, s15 @ int
        bx      lr
useStandard(float):
        vrinta.f32      s0, s0
        vcvt.s32.f32    s15, s0
        vmov    r0, s15 @ int
        bx      lr

If you change the return value to float the standard one collapses to
Code:
useStandard(float):
        vrinta.f32      s0, s0
        bx      lr
 
roundf() expects a float. I think it will not return the same value in any case.

And wether we can just return float is the question.. I do not know what would speak against it - but it is different from Arduino


Edit: and it needs a #include <math.h> or <cmath>
 
Last edited:
Status
Not open for further replies.
Back
Top