Fast Sine calculation

Other misc things
Post Reply
andydansby
Member
Posts: 37
Joined: Fri May 27, 2016 8:58 pm

Fast Sine calculation

Post by andydansby »

While playing around with the Z88dk Sine function, I started to try to search for a faster algorithm. I found on a defunt message board (through archive.org) a pretty faster alternative Sine function that operates nearly twice the speed of the Z88dk version. So, I wanted to post this to share. Enjoy.

Code: Select all

//      zcc +zx -vn -SO3 -m -lm -clib=new main.c -o 1sine -startup=9 -create-app
//https://web.archive.org/web/20130927121234/http://devmaster.net/posts/9648/fast-and-accurate-sine-cosine

//#pragma printf %f %ld %d

#include <arch/zx.h>
#include <math.h>
#include <float.h>
#include <stdio.h>
#include <input.h>
#define ABS(N) ((N<0)?(-N):(N))
const float PI = 3.141592;

float freq = 2;
unsigned char yHeight = 191;//height of the display
unsigned char xWidth = 255;//width of the display
int halfHeight = yHeight / 2;
float sinCalc;
int x, y;
float yy;
Next, here's the plot code and drawing the center line.

Code: Select all

void plot (unsigned char x, unsigned char y)
{
    //
	if (x > 255)	return;
	if (y > 192)	return;

	*zx_pxy2saddr (x,y) |= zx_px2bitmask(x);
}

void drawCenterLine (void)
{
    //draw straight  dashed line 
	for (x=0; x<= xWidth; x+=2)
	{
		plot(x, halfHeight);
	}
}
First Test with the Z88dk version of sine

Code: Select all

float sine_caller ()//standard SIN calculation
{
	sinCalc = sin( x * freq * PI / xWidth );
	yy= ( ( sinCalc + 1.0) * (yHeight - 1) / 2.0);
	y = (int)  yy;
	return y;
}

void z88dk_sine (void)
{
	for (x=0; x <= xWidth; ++ x)
	{
		sine_caller();
		plot(x, y);
	}
}
Now test with the fast sine routine.

Code: Select all

float _sine_Smile(float xx)
{
	//http://devmaster.net/posts/9648/fast-and-accurate-sine-cosine
    //this routine was found by user Smile, don't know where
    //the algorithm comes from

    //const float P = 0.225;//now not used with A and B being precalculated
    const float A = 7.5888;//A = 16 * sqrt(P);
    const float B = 1.634;//B = (1 - P) / sqrt(P);

    yy = xx / DOUBLEPI;

    yy = yy - floor(yy + 0.5);

	yy = A * yy * (0.5 - ABS(yy));

	return yy * (B + ABS(yy));
}

void sine_Smile (void)
{
    // this routine IS compatible with frequency yet
	//freq = 2.0;// 2.0

	for (x=0; x <= xWidth; ++ x)
	{
		sinCalc = _sine_Smile(x * freq * PI / xWidth);
        YY = ( ( sinCalc + 1.0) * (halfHeight));
        y = (int)YY;
		plot(x, y);
	}
}
Finally, our main

Code: Select all

void main()
{
	__asm
	ei
	__endasm

	zx_cls(PAPER_WHITE | INK_BLUE);
       z88dk_sine ();//sine routine
      //sine_Smile();//fast sine routine
}
Enjoy
Andy
User avatar
dom
Well known member
Posts: 1413
Joined: Sun Jul 15, 2007 10:01 pm

Re: Fast Sine calculation

Post by dom »

That's interesting - it looks like an approximation that works if the input value is constrained in someway?

There's math16 available which might be of interest to you - it implements a 16 bit IEEE-754 data type which should be significantly faster than any of the other maths libraries for this sort of example. The trig functions use 3 (I think) rounds of the Horner method. It's exposed as a native __Float16 type in sccz80 but in sdcc you have to use the utility functions. There's info and a versus genmath screenshot comparison here: https://github.com/z88dk/z88dk/wiki/Cla ... 80z180z80n
stefano
Well known member
Posts: 1680
Joined: Mon Jul 16, 2007 7:39 pm

Re: Fast Sine calculation

Post by stefano »

There's also an integer simplification in lib3d, if you're interested in speed. Some of the examples use it.
stefano
Well known member
Posts: 1680
Joined: Mon Jul 16, 2007 7:39 pm

Re: Fast Sine calculation

Post by stefano »

Post Reply