Function for approximating a sine signal I want to approximate a sine signal with a parabola, which is given by the function:

$$f(x) = 0.4053 \cdot x \cdot (3.1415 - x) \space\text{for}\space 0 \le x \le 3.1415$$

In a first approach, I wrote the following code which works fine:

float sin1(int phase)
{
    if(phase % 1000 &lt;= 500)
    {
    return(0.4053*2*3.1415*(phase % 1000)/1000*(3.1415 - 2*3.1415*(phase % 1000)/1000));
    }
    else
    {
    return(-0.4053*2*3.1415*(phase % 500)/1000*(3.1415 - 2*3.1415*(phase % 500)/1000));
    }
}


As I want to use this function on a microcontroller, I'm interested in how to optimize this code regarding memory consumption and performance.
how to optimize this code regarding memory consumption and performance. (?)



Consider redefining the angle measurement.  It appears int phase is 0.36 degrees.  A natural choice would be 1024 phase to 1 revolution.  Now the problem becomes one using a binary angle measure. Not only does this simplify small things like scaling, it opens up coding choices  as there are many trig function code bases designed withs BAMS, Binary Angular Measurement System.
Code uses double constants and so makes for likely slower computation on an embedded system.  If all that is needed is float, uses float constants and float math.

// return(0.4053*2*3.1415*(phase % 1000)/1000*(3.1415 - ...
return(0.4053f*2*3.1415f*(phase % 1000)/1000*(3.1415f ...

OP reports phase guaranteed to be positive. yet it is minor to adjust code for full int range.

// if(phase % 1000 &lt;= 500)
phase %= 1000;
if (phase &lt; 0) phase += 1000;
if (phase &lt;= 500)

Accuracy: Using 3.1415 for machine_pi can be improved at no computational cost by using  #define MACHINE_PI 3.141592653589793f.  This will improve the end points in the 5th or 6th decimal place.  Use 0.405284734572655f instead of 0.4053 to insure sine(90° (250 phase)) is 1.0f.
If your processor lacks a built-in FP hardware, I recommend a fast integer only solution.  e.g. CORDIC or a small linear interpolation should only low precision be needed.




Using a parabola model like OP's  (1 cycle = 1024 BAM).  The below code is effectively the same preciseness as OP's code with only integer math: and, or, +, -, *, negate and shift.

Input  range [0R 2πR]  mapped to [0 to 1024]
Output range [-1.0 1.0] mapped to [-16,384 16,384]

int_fast16_t sin_bam(int angle_bam) {
  angle_bam %= 1024;
  if (angle_bam &lt; 0)
    angle_bam += 1024;
  uint_fast16_t sub_angle = angle_bam % (1024u / 2);
  int_fast16_t sn = unsigned_mult16x16_into_32(sub_angle, (1024/2 - sub_angle)) / 4;
  if (angle_bam &amp; 512) {
    sn = -sn;
  }
  return sn;
}