Execution Speed of the Teensy 3.1

Status
Not open for further replies.
Yeah, evidently -fsingle-precision-constant has been in for a while, but then GCC has too many switches (spoken as somebody who has added his own share over time). :cool:
 
...but does'nt this break compatibility with existing projects ?

It depends on how many projects use floating point constants that do not fit in an IEEE 754 single precision without loss of precision (i.e. 1.2f has fewer bits of precision than 1.2, but 53f would be fine). It depends on how accurate people need things. I'm sure there are some people who are not porting broken Arduino code, and really expect double to be 64-bits with full precision.
 
Yeah, I've heard from quite a few people who really do need 64 bit double precision.

But I've also recently taken a better look at performance issues. Constants being treated as double are forcing a lot of very ordinary code to all promote to slower 64 bits, even when the result is just assigned to a 32 bit float. That'll seem even worse when we have a single precision FPU, just sitting there unused in so many common/casual cases.

I'm probably going to put -fsingle-precision-constant into Teensyduino 1.25...
 
I've just updated the files to use -fsingle-precision-constant. I hope to have a first 1.25 beta out in a few days.

Another common issue with 32 vs 64 bit is the common trig functions. LOTS of Arduino sketches use sin(), cos(), log(), rather than sinf(), cosf(), logf().

Is there any way to create a set of C++ overloaded functions that call the "extern C" ones?

Code:
float sin(float x) { return sinf(x); }
double sin(double x) { return sin(x); }  // how to call the "extern C" sin() ??
 
Assuming you optimize, you could do something like:

Code:
#define __MATHFUNC__(X, FLT, DBL, LDBL)                                 \
((sizeof (X) == sizeof (double))                                        \
 ? ((__typeof__ (X)) (DBL) ((double)(X)))                               \
 : ((sizeof (X) == sizeof (float))                                      \
    ? ((__typeof__ (X)) (FLT) ((float)(X)))                             \
    : ((__typeof__ (X)) (LDBL) ((long double)(X)))))

#ifdef __cplusplus
extern "C" {
#endif

extern double sin (double);
extern float sinf (float);
extern long double sinl (long double);

extern double cos (double);
extern float cosf (float);
extern long double cosl (long double);

#ifdef __cplusplus
};
#endif

#define sin(X) __MATHFUNC__ (X, sinf, sin, sinl)
#define cos(X) __MATHFUNC__ (X, cosf, cos, cosl)

This way on the ARM, if you call sin and are passed a double, it will call sin. If you are passed a float, it will call sinf, and if/when they support long double being IEEE 128-bit on ARM, if passed a long double, it will call sinl. On the AVR, it will always call sin because the size of float, double, and long double are all the same size. You need to make sure that there are proper extern "C" declarations of each flavor of the math functions before the macros are defined.

One tricky aspect is putting the calls to the double, float, and long double variants (DBL, FLT, and LDBL) inside of ()'s. This prevents re-expansion of the sin, cos, etc. macros when you are calling the function.

Here is the test code that tests whether the 3 functions are called via inspection of the asm file:

Code:
float flt_sin (float x)
{
  return sin (x);
}

double dbl_sin (double x)
{
  return sin (x);
}

long double ldbl_sin (long double x)
{
  return sin (x);
}
 
Last edited:
Maybe with rebuilding the newlib?

And I remember a gcc switch like "short-doubles". (I can't remember the exact name or what it does exactly, only that it requires to rebuild the newlib...)
 
Last edited:
I prefer that the behavior remain standard and tell people that if they want better performance, put a "f" after their floating point constants and math routines.
 
Status
Not open for further replies.
Back
Top