I was interested to run some benchmarks on the code I’m developing for the project discussed in this thread. I was using the code that was originally used to compare the performance of ROBOTC and EasyC back in 2011 from here. One of the benchmarks creates a LUT using the “pow” function, back in 2011 ROBOTC was shown to be about twice as fast as EasyC, this was the code used for the benchmark.
/*------------------------------------------------------------------------*/
/* Create a power based lut */
/*------------------------------------------------------------------------*/
// Use a default of 20 if not already defined
#define MOTOR_LUT_FACTOR 20.0
#define MOTOR_LUT_OFFSET 10
// lookup table for non linear control
int MotorLut[128];
void
MakeLut()
{
int i;
float x;
for(i=0;i<128;i++)
{
// check for valid power base
if( MOTOR_LUT_FACTOR > 1 )
{
x = pow( MOTOR_LUT_FACTOR, (float)i / 127.0 );
if(i >= (MOTOR_LUT_OFFSET/2))
MotorLut* = (((x - 1.0) / (MOTOR_LUT_FACTOR - 1.0)) * (127-MOTOR_LUT_OFFSET)) + MOTOR_LUT_OFFSET;
else
MotorLut* = i * 2;
}
else
{
// Linear
MotorLut* = i;
}
}
}
task main()
{
while(true)
{
SensorValue[dgtl1 ] = 1;
MakeLut();
SensorValue[dgtl1 ] = 0;
}
}
RobotC time 14mS
EasyC time 31mS
When I ran this in the framework I’m developing it also runs in about 30mS, this is not surprising as both EasyC and my code are compiled with the gcc compiler and use the standard gcc math library. I was interested to see what improvement could be made with an optimized version of the math library, there is an alternative called the fast math library but this does not include a faster version of pow. A bit of googling and I came across this web site.
http://www.machinedlearnings.com/2011/06/fast-approximate-logarithm-exponential.html**
Paul has created some fast approximations for log, exponential and power functions, specifically for pow this can be used as a replacement.
/*=====================================================================*
* Copyright (C) 2012 Paul Mineiro *
* All rights reserved. *
* *
*=====================================================================*/
static inline float
fastpow2 (float p)
{
float offset = (p < 0) ? 1.0f : 0.0f;
float clipp = (p < -126) ? -126.0f : p;
int w = clipp;
float z = clipp - w + offset;
union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };
return v.f;
}
static inline float
fastlog2 (float x)
{
union { float f; uint32_t i; } vx = { x };
union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
float y = vx.i;
y *= 1.1920928955078125e-7f;
return y - 124.22551499f
- 1.498030302f * mx.f
- 1.72587999f / (0.3520887068f + mx.f);
}
static inline float
fastpow (float x,
float p)
{
return fastpow2 (p * fastlog2 (x));
}
Using “fastpow” as a replacement for “pow” in the benchmark allows the MakeLut function to run in approximately 5mS, an improvement of x6 over the standard library and almost three times faster than ROBOTC. These functions are all compatible with EasyC and should be considered for any math heavy calculations.*