;Generic polynomial calculator

;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
******  Generic polynomial calculator **************
;Short name GPC_

;This function calculates a polynomial function from an argument supplied in W
;and polynomial coefficients supplied in a table in NVEM0.
;The result is returned in W.

;Entry points:
	GPC_Calculate	;Calculate polynomial value

;Before calling (GoSub) GPC_Calculate you must load
;
;	W 	 = The argument value (normally called X)
;	NVEMPtr  = Control table address

The function alters:
;		Data stack
;		W
;		NVEM control registers

;Instruction count approx 10 + 6*N, where N is the polynomial order
;(For estimating how many instructions a MultiTrack task executes before yielding)

;The control table format is

;	NV0Byte		N		;The order of the polynomial
;	NV0fNum		An		;The X^n coefficient
;	NV0fNum		An-1		;The X^(n-1) coefficient
;   ....
;	NVfNum		A1		;The X coefficient
;	NVfNum		A0		;The constant

;Example: 	The polynomial Y = 1.4 * x^4  - 1.3 * x^3  + 1.2 * x^2   - 1.1 * x  + 1
;		is a 4th order polynomial. It's control table would be

;		NVEM0			;It must be located in NVEM0, which must be at the end of your program
;
;PolyTab:	NV0Byte		4	;Fourth order
;		NV0fNum		1.4	;Coefficient for x^4
;		NV0fNum		-1.3	;Coefficient for x^3
;		NV0fNum		1.2	;Coefficient for x^2
;		NV0fNum		-1.1	;Coefficient for x^1
;		NV0fNum		1.0	;Constant

;The calculation is performed on the simplified version of the polynomial, 
;reducing it to one multiply and one addition per term. This is also less prone to
;accuracy problems, as it avoids small differences between possibly large numbers.

;	Result =  (((A4 * x + A3) * x + A2) * x + A1) * x + A0

;How to use this function:

;	1.	Copy and paste the code between vvvvvvvvvvvvvv and ^^^^^^^^^^^^^^^^^^^
;		into your program

;	2.	At the end of your program, in NVEM0, build the polynomial coefficient table
;		Use the example above as a prototype.
;
;	3.	In your program invoke the function as per this example code:

;		fRecallW	fArgument	;Load the argument into W
;		NVSetPtr	PolyTab		;Point to coefficient table
;		GoSub		GPC_Calculate	;Calculate
;		fStore		fResult		;Save the result from W


fGPC_TempX:	defFLOAT		;Scratch memory
bGPC_Count:	defBYTE

GPC_Calculate:
		fStore		fGPC_TempX	;Save argument
		NVSetpage	0
		NVSetRecNum	0
		NVSetRecLen	4
		NVPushByte	0		;Get the order of the poly to X
		Store		bGPC_Count	
		NVAddPtr	1		;Now points to first coefficient


		NVfReadW	0		;Get first coefficient
GPC_Loop:
		NVAdvPtr			;Ready for next time
		fRecallQ	fGPC_TempX	;Argument
		fMul
		NVfReadQ	0		;Get next coefficient
		fAdd
		DMGNZ		bGPC_Count,GPC_Loop	;Test if all done
		Return
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;Test table
		NVEM0			;It must be located in NVEM0, which must be at the end of your program
PolyTab:	NV0Byte		4	;Fourth order
		NV0fNum		1.4	;Coefficient for x^4
		NV0fNum		-1.3	;Coefficient for x^3
		NV0fNum		1.2	;Coefficient for x^2
		NV0fNum		-1.1	;Coefficient for x^1
		NV0fNum		1.0	;Constant
