westaust55
Moderator
Having noted comments/requests for an "improved Square-root function by forum members, and not having spied a routine posted to date,
below is a basic routine for calculating a square root of an integer number from 1 to 65535 to 2 decimal places.
I stopped at two decimal places for 2 reasons:
(a) the integer part can be up to 3 digits (255), which in a word variable leaves 2 for the mantissa/decimal part
(b) the divisors become larger than 65535 after 2 decimal places which would further complicate the maths
Nevertheless the 2 decimal place format and multiplied by 100 is in keeping with the PICAXE inbuilt Sin and COS functions.
Even to 2 decimal places, some internal math can exceed 65535 (numbers like ~500,000 occur) so overflow checking is required.
The code can no doubt be compressed but left as posted so that others may be able to understand how it functions.
The code did become shorter after I realised that the remainder determined from
below is a basic routine for calculating a square root of an integer number from 1 to 65535 to 2 decimal places.
I stopped at two decimal places for 2 reasons:
(a) the integer part can be up to 3 digits (255), which in a word variable leaves 2 for the mantissa/decimal part
(b) the divisors become larger than 65535 after 2 decimal places which would further complicate the maths
Nevertheless the 2 decimal place format and multiplied by 100 is in keeping with the PICAXE inbuilt Sin and COS functions.
Even to 2 decimal places, some internal math can exceed 65535 (numbers like ~500,000 occur) so overflow checking is required.
The code can no doubt be compressed but left as posted so that others may be able to understand how it functions.
The code did become shorter after I realised that the remainder determined from
Remaind = x - ( sqr(x) * sqr(x) )
was always the same value as the remainder calculated by the math procedure and thus could be calculated in a couple of lines rather than many steps.
Code:
; Calculate square root of an integer number from 1 to 65535
;
; The result ia a value to 2 decimal places multiplied by 100
;
; Thus:
; sqr (2) = 2.14 and is given as 214
; sqr (12358 = 111.16 and is given as 11116
; sqr (65535) = 255.99 and is given as 25599
; The routine is based on the methods described on various
; internet sources such as:
; www.solving-math-problems.com/calculate square root
; www.homeschoolmath.net/teaching/square-root-algorithm
;
;
; Picaxe program routine created by
; Westaust55 (Perth, Western Australia)
;
;
; Date: 30 Oct 2011
; Rev: 0
;
#PICAXE 40X1
#NO_DATA
#NO_TABLE
SYMBOL x = w4
SYMBOL Remaind = w5
SYMBOL Intern1 = w6
SYMBOL OvrFlow = w7
SYMBOl Factor = w8
SYMBOL Result = w9
SYMBOL Counter = b24
SYMBOL Digit = b25
SYMBOL Hunths = b26
SYMBOL Charact = b27
; start of the program example
Main:
; Entry of a value
DataEntry:
SERTXD ( "Input an value:")
SERRXD [65000], #x ; early 40X1 parts Must have the timeout - PE tells you so!
SERTXD (cr,lf,"Entered Value: ", #x, cr,lf)
Charact = SQR x ; Find the Characterist/Integer part using inbuilt function
Remaind = Charact * Charact ; determine the Remainder
Remaind = x - Remaind
Result = 0 ; Clear the mantissa/demical part in case multiple calls
If Remaind = 0 Then Finalise ; If Remainder is 0 then nothing more to do
; Calculate the mantissa/decimal part to 2 decimal places
FOR Counter = 1 TO 2 ; one pass for each decimal place required - STOP AT 2
Factor = Charact ; here we start to determine a new divisor
FOR Digit = 1 to Counter ; calculate 20 * Sqrt including current decimal places
Factor = Factor * 10
NEXT Digit
Factor = Result * 10 + Factor * 2 ; close, but we have still to add the units part
Intern1 = Remaind * 100 ; we temporarily use var Intern1 in case we need to adjust
OvrFlow = Remaind ** 100 ; check if we overflow the 65535 word variable limit
IF OvrFlow > 0 THEN
Factor = Factor / 10
Intern1 = Remaind + 5 /10 * 100 ; 5 is to round-up
ENDIF
Remaind = Intern1
Digit = Remaind / Factor ; a first pass but need to check may be too high
DO
Intern1 = Factor + Digit * Digit
IF Intern1 > Remaind THEN
DEC Digit ; too high so decrement the next digit of the square root
ENDIF
LOOP UNTIL Remaind >= Intern1
Remaind = Remaind - Intern1 ; calculate the new remainder
Result = Result * 10 + Digit ; merge the next decimal digit into the result
NEXT Counter
Finalise:
Result = Charact * 100 + Result ; add in the Characteristic (ie Integer) part
SERTXD ("Sqrt = ", #Result, cr, lf)
GOTO Main