Calculate Cube Root to 2 decimal places

westaust55

Moderator
As a follow on the my past calculation of a square root for values (0 - 65535) to two decimal places, I have prepared a similar piece of PICAXE BASIC code to calculate the cube root of a value (0 to 65535) to two decimal places.

I stopped at two decimal places as the maths is at 2 decimnal places already using 32-bit numbers with intermediate math values up to 100 million and for a thord decimal place
These values could be as high as 10,000 million which exceeds the capacity of a 32-bit value.

The 2 decimal place format and result multiplied by 100 is in keeping with the PICAXE inbuilt SIN and COS functions.

Due to the 32-bit maths, the code does utilise virtually every byte/word variable for the X1 and M2 part.
Therefore when used as part of a larger program it will be necessary to save all the byte vairbale b0 to b27 to RAM before performing this routine and having just the oriignal value in word variable "X".

Below is the PICAXE BASIC routine for calculating a cube root of an integer number from 0 to 65535 to 2 decimal places.
The code can no doubt be compressed, but left as posted so that others may be able to understand how it functions.
As posted it occupies 312 bytes of program space.

Code:
; Calculate cube root of an integer number from 0 to 65535
;
; The result is a value to 2 decimal places multiplied by 100
;
; Thus:
; CuRt (2)     =  1.25992 and is given as  125
; CuRt (100)   =  4.64158 and is given as  464
; CuRt (1000)  = 10.00000 and is given as 1000
; CuRt (21000) = 27.58924 and is given as 2758
; CuRt (43210) = 35.09092 and is given as 3509
; CuRt (65535) = 40.31727 and is given as 4031

; The routine is based on the hand calculation methods  
; described on various internet sources such as:
; http://www.mathpath.org/Algor/cuberoot/algor.cube.root.htm
;
;
;   
; Picaxe program routine created by
; Westaust55 (Perth, Western Australia)
;
;
; Date: 10 March 2013
; Rev: 0
;
#PICAXE 40X1
#NO_DATA
#NO_TABLE

SYMBOL ThisDig    = b1
SYMBOL       x    = w2
SYMBOL Thousands  = w3 ; Holds the thousands part of the enter value (if > 999)
SYMBOL ThouModul  = w4 ; Hold the units, tens, hundreds digits
SYMBOL HighRemdr  = w5 ; High word of a 32 bit value as remainder during calcs
SYMBOL LowRemdr   = w6 ; Low  word of a 32 bit value as remainder during calcs 
SYMBOL HighVal    = w7 ; High word of a 32 bit value during calcs for next digit
SYMBOL LowVal     = w8 ; Low word of a 32 bit value during calcs for next digit
SYMBOL HighValHold= w9
SYMBOL LowValHold = w10
SYMBOL InterVal   = w11
SYMBOL Result     = w12 ; Word variable wher the cube root to 2 decimal places is built up
SYMBOL Digit      = b26 ; Used as index for FOR...NEXT loop in main program
SYMBOL Value      = b27 ; Used as index for FOR...NEXT loop in subroutine


; start of the program example
Main:
; Entry of a value
DataEntry:
	SERTXD ("Input a value (0 to 65535): ", cr,lf)
	SERTXD ("Enter in quotes", cr,lf)
	SERRXD   [65000], #x		; early 40X1 parts Must have the timeout - PE tells you so!
	SERTXD (cr,lf,"Entered Value: ", #x, cr,lf)

	Thousands = x / 1000			  	; extract the thousands part as a value
	ThouModul = x // 1000			  	; extract the hundreds, tens, units part as a value
	HighRemdr = 0
	LowRemdr  = Thousands
	Result    = 0				  	; Clear the result

	FOR Digit = 0 to 3
		GOSUB FindThisDigit		  	; Find the next digit that matches the cube root
		Result = Result * 10 + ThisDig  	; advance the remainder along one digit and add in the new units digit
		Thousands  = LowRemdr 		  	; use 'thousands' value as no longer required
		LowRemdr = LowRemdr - LowValHold
		IF LowRemdr > Thousands  THEN   	; test for underflow down through zero to new higher value
			DEC HighRemdr		  	; if there was underflow then adjust the high word of 32-bit value
		ENDIF
		InterVal = LowRemdr ** 1000	  	; we need to multiply by 1000 - determine what overflow form low word to high word
		LowRemdr = LowRemdr * 1000	  	; determine the remainder within the low word of 32-bit value
		HighRemdr = HighRemdr - HighValHold * 1000 + InterVal ; then adjust the high word of 32 bit value
		
		Thousands  = LowRemdr		  	; hold the low word of remainder for overflow test
		IF Digit = 0 THEN			  	; if completing the first digit then there may be a modulus 1000 value from original value to add in	
			LowRemdr = LowRemdr + ThouModul  ;Add in the modulus 1000 part from orignal value 
			IF LowRemdr < Thousands THEN  ; if there is overflow
				INC HighRemdr		; thena djust the high word of 32-bit remiander
			ENDIF
		ENDIF
	NEXT Digit						; return for next digit until up to 2 decimal places are done		
			
Finalise:
		SERTXD ("Cube Root = ", #Result, cr, lf)
		GOTO Main
;
; ===== Subroutine to determine the value for the next digit		
FindThisDigit:
  	ThisDig = 0
  	HighValHold = 0
  	LowValHold = 0
	FOR Value = 1 to 9 			  	; result for Value= 0 is always 0, so start at 1
		InterVal = Result * 10 + Value * Value
				
		LowVal   = 30 * Result 		  	; a temporary intermediate use of LowVal variable
		HighVal  = LowVal ** InterVal	  	; determine the upper word of the 32 bit value
		LowVal   = LowVal *  InterVal	  	; determine the lower word of the 32 bit value
		
		InterVal = Value * Value * Value 	; Last part of equation to add into 32-bit value

		thousands  = LowVal 		  	; use 'thousands' value as no longer required
		LowVal     = LowVal + Interval 	 ; add last part into lower word of 32-bit number
		IF LowVal < thousands THEN 	 	 ; test if roll over occurred due to addition
			INC HighVal 		 	 ; if so, then adjust high word of 32 bit number
		ENDIF	
  	
  		IF HighVal > HighRemdr THEN Exit 	; This digit value is TooHigh      
  		IF HighVal = HighRemdr AND LowVal > LowRemdr THEN EXIT ; This digit value is TooHigh
  		
  		ThisDig = Value			  	; this digit value would be okay, so save the digit value
  		HighValHold = HighVal			; the the resultant 32-bit value to deduct from remainder
  		LowValHold = LowVal
  	NEXT Value	
  	RETURN
; ============================================================
EDIT:
A couple of other math functions I have provided code for back in 2011 are as follows:

Square Root to two decimal places: http://www.picaxeforum.co.uk/showthread.php?19714-Calculate-Square-Root-to-two-decimal-places

Log (base 10) to two decimal places: http://www.picaxeforum.co.uk/showthread.php?19695-Calculate-Logarithms-with-PICAXE-math

Note that you can use a constant factor to convert from Log to Ln (natural log - base e).
 
Last edited:

westaust55

Moderator
Following a recent PM on what is the use of the cube root function,
I was wondering what someone could use that for in a practical application.
I provide the following comment from my own work which often must tie in with mechanical engineers:

In the engineering field, there are a number of occurrences requiring the cube function. Thus when calculating in reverse, we need the cube root function.

For example, for many fans and pumps, the Power demand/draw is proportional to the cube of the fan/pump rotational speed.​
 
Top