[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