[sdiy] Approximating sine with plain integer math

ASSI Stromeko at nexgo.de
Thu Apr 7 22:27:11 CEST 2016


On Wednesday 06 April 2016, 15:55:37, John Ames wrote:
> 1. Generate a sawtooth in the range -max to +max (i.e. -32768 to 32767
> for a 16-bit integer.)
> 2. Square it.
> 3. Divide by +max (i.e. 32767.)

You don't want to divide on any microcontroller.

> 4. Multiply by the sign of the original value.

You don't need to do this either since you can fold it into the calculation.

> 5. Subtract the original value.
> 6. Multiply by 4.

Left shift by 2 places (the optimizer will probably infer it for you).

> int sawToSine(int saw)
> {
>     return ((((saw * saw) / INT_MAX) * (saw / abs(saw))) - saw) * -4;
> }

This is wrong on many levels.  You clearly need a 32bit intermediate result 
for the multiplication, so sizeof(int)>=4. Instead of the division by 
SHORT_MAX (which is the constant you actually want to use) you could use a 
right shift by 15 (the resulting range is a tiny bit smaller).  You really 
don't want to rely on

sign(saw) = (saw/abs(saw))

especially since there's a singularity when saw is zero.  But you don't need 
that anyway since

saw * abs(saw)

already has the correct sign and will be optimized quite easily.

It's actually a bit easier to do this with unsigned integers and a separate 
sign bit, since the division could then be done by simply picking the high 
word from the multiplication result (which may not actually be faster than 
the bit shift depending on what uC you're doing this on).

> Whether this is any faster than using floating-point probably depends
> on how expensive integer multiplies and divides are on your target
> architecture, but I just thought it was interesting and wanted to
> share :)

You only need one multiply and some shifts or word extractions anyway.  The 
approximation you're implementing is actually

sign(x) * ( 2*abs(x) - x^2 )

with some suitable scaling of x.  Here's one place where it has been 
discussed before:

http://forum.devmaster.net/t/fast-and-accurate-sine-cosine/9648

(I thought I had another much older link to either the same or a very 
similar formula, but I can't find it :-( )


Regards,
Achim.
-- 
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+

Waldorf MIDI Implementation & additional documentation:
http://Synth.Stromeko.net/Downloads.html#WaldorfDocs




More information about the Synth-diy mailing list