Does This Method Provide The Exact Same Return As SPINs Square Root Operator
idbruce
Posts: 6,197
Hello Eveyone
While I am not working on my 3D printer, I have been spending some time porting certain sections of the Teacup firmware for 3D printing, from C/C++ to SPIN. One of the functions that I am porting obtains the square root of an integer, and I am wondering, if all this code is really necessary, since SPIN already has a square root operator. At the beginning of the code, there is a comment about the return of the function and it has me concerned about the return value, and if it would be identical to using the SPIN operator:
\return sqrt(a - 1) < returnvalue <= sqrt(a)
EDIT: In other words... On the surface, it appears that it would return the same, but would SPIN have a similar expression, or is there any possibility they could offer different results.
The Propeller Manual states:
While I am not working on my 3D printer, I have been spending some time porting certain sections of the Teacup firmware for 3D printing, from C/C++ to SPIN. One of the functions that I am porting obtains the square root of an integer, and I am wondering, if all this code is really necessary, since SPIN already has a square root operator. At the beginning of the code, there is a comment about the return of the function and it has me concerned about the return value, and if it would be identical to using the SPIN operator:
\return sqrt(a - 1) < returnvalue <= sqrt(a)
EDIT: In other words... On the surface, it appears that it would return the same, but would SPIN have a similar expression, or is there any possibility they could offer different results.
The Propeller Manual states:
Square Root ^^
The Square Root operator returns the square root of a value. Square Root can be used in both variable and constant expressions. When used with variable expressions or integer constant expressions, Square Root returns the 32-bit truncated integer result. When used with floating-point constant expressions, Square Root returns the 32-bit single-precision floating-point result. Example:
X := ^^Y
Square Root becomes an assignment operator when it is the sole operator to the left of a variable on a line by itself. For example:
^^Y
This would store the square root of the value of Y back into Y.
CON _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 'Full Duplex Serial Pin Assignments TX = 30 RX = 31 'Full Duplex Serial Driver Constants COMM_MODE = 0 COMM_BAUD_RATE = 115_200 VAR 'Global variables for the IntegerSquareRoot method BYTE bIntSqRt_C BYTE bIntSqRt_Z BYTE bIntSqRt_J BYTE bIntSqRt_Y2 WORD wIntSqRt_B WORD wIntSqRt_X WORD wIntSqRt_I WORD wIntSqRt_Y2 LONG lIntSqRt_Y2 OBJ Terminal: "FullDuplexSerial" PUB Main | SquareRoot 'Start FullDuplexSerial Terminal.Start(RX, TX, COMM_MODE, COMM_BAUD_RATE) WAITCNT(CNT + (1 * CLKFREQ)) SquareRoot := IntegerSquareRoot(603729) Terminal.Dec(SquareRoot) PUB IntegerSquareRoot(IntSqRt_A) { \param a find square root of this number \return sqrt(a - 1) < returnvalue <= sqrt(a) } wIntSqRt_B := IntSqRt_A >> 16 bIntSqRt_C := wIntSqRt_B >> 8 wIntSqRt_X := 0 bIntSqRt_Z := 0 bIntSqRt_J := $8 REPEAT WHILE bIntSqRt_J bIntSqRt_Z |= bIntSqRt_J bIntSqRt_Y2 := bIntSqRt_Z * bIntSqRt_Z IF bIntSqRt_Y2 > bIntSqRt_C bIntSqRt_Z ^= bIntSqRt_J bIntSqRt_J >>= 1 wIntSqRt_X := bIntSqRt_Z << 4 wIntSqRt_I := $8 REPEAT WHILE wIntSqRt_I wIntSqRt_X |= wIntSqRt_I wIntSqRt_Y2 := wIntSqRt_X * wIntSqRt_X IF wIntSqRt_Y2 > wIntSqRt_B wIntSqRt_X ^= wIntSqRt_I wIntSqRt_I >>= 1 wIntSqRt_X <<= 8 wIntSqRt_I := $80 REPEAT WHILE wIntSqRt_I wIntSqRt_X |= wIntSqRt_I lIntSqRt_Y2 := wIntSqRt_X * wIntSqRt_X IF lIntSqRt_Y2 > IntSqRt_A wIntSqRt_X ^= wIntSqRt_I wIntSqRt_I >>= 1 RETURN wIntSqRt_X
Comments
Thanks for the response.
Although I do not believe I have ever used it, but I may have once or twice, I believe that C/C++ has operators readily available for square roots. This function must have a special purpose, otherwise I cannot imagine someone taking the time to code it all out.
I am just wondering if rounding/truncating is the basis for writing this function in the first place. So instead of being errors, it could possibly be the desired effect.
Rather those functions are provided by libraries. The standard libraries. Hence you will often see "#include <math.h>" in C sources.
One may well want to write ones own square root and other such functions if those standard libraries are not available. I have no idea what is available in the Arduino environment for example.
Or one may do that to get some extra optimization in some cases. Or perhaps you are using some fixed point number format and need specialized functions that work with that.
You could always do some tests to see what different results they produce, if any. Just run the C and Spin codes against a set of random numbers and see what happens.
Anyway in may applications the odd bit up or down in rounding won't make any noticeable difference.
I had forgotten about #include <math.h>, which I have used in the past and was an oversight on my part. Thanks for setting me straight
Hmmmm.... You stated that very well Heater! Your first reason makes a lot of sense and seems like the primary reason, however I believe you are correct about the second one also. I believe it is a combination of both of those reasons.
EDIT: Or should I say that since it had to be written, might as well take the time to optimize it.
I would have to agree. Thanks for your input.
y := ^^( x + ^^x )
Jonathan
Jonathan, thanks for the snippet. By the way, what is your part in the KISSlicer project? I will be using that software to create my GCODE.
So feel free to use Spin's ^^ operator. It matches exactly.
Thanks for the testing and info, I certainly appreciate it.
I don't know where you got that code, but it is different then the code I have, however I downloaded mine about 9 months ago, so it may have changed, and github won't allow my old browser in for some odd reason, so I cannot get the latest code. Anyhow, this is what I started with:
It surprises me that you have those files at your disposal. Do you have an interest in Teacup?
I believe Loopy looked at porting this to the Prop several months ago, and I looked at the code back then. I'm not planning on doing any 3D printing in the near future, but I do have some interest in what other people are doing with 3D printing.
After reviewing some previous documentation pertaining to Teacup, I rediscovered this summarization, which outlines the processing of key information.
Source: Wikipedia - http://reprap.org/wiki/Teacup_Firmware
There is some good documentation, source code, and hyperlinks, within the Teacup firmware, however I still firmly believe that differences in architecture will make a direct porting inefficient, as the example at hand clearly demonstrates, or should I say as Dave has so kindly proven. I think the previous summarization and portions of the Teacup firmware, should be used as a roadmap for creating a new firmware that is unique to the architecture of the Propeller chip.
I now believe that once this method is ported, it should provide a well rounded overview of what is really necessary for some Propeller firmware, by working within the expansive boundaries of Propeller chip, and utilizing it to it's full potential, for this particular type of application.
Of course, the rest of dda.c will need to be ported, but much of the remaining code will be changed.
Just $0.02 worth.
There has been a lot of progress recently, a lot of people have been providing useful feedback and bug reports and feature requests, etc. Have you tried the 1.5 Beta 2.xx on the forums?
Sorry to hijack the thread, everybody.
Jonathan
No, I am still currently building and testing portions of the printer.
In my opinion, there is just too much junk that I do not want or need, which just eats up valuable resourses. Additionally, in the form of raw firmware, considering the complexity of the code, I doubt that I would be able to make it work, with the added factor, that there is just some things that I would like to do differently.
To be perfectly honest, over the last 2 weeks, I have been all over the place with my thinking, first port and then don't port. For the most part, any attempt at a port just gives me a much better understanding of the code. However a couple of days ago, I really started digging deep into the source code, tracking the process and events, and I believe I walked away with a good deal of knowledge (maybe ). Anyhow, for now, at this point in time, I have decided to write my own firmware for the Propeller from scratch, using the Teacup firmware as a guide in the right direction.
I do not know if you noticed, but I recently released a new stepper driver object within the forum. I am currently modifying that stepper driver once again, to be of more use as a 3D printer or CNC driver, so that I may use it in the future firmware, but I am running into problems, because I have forgotten some stuff about cog usage and variables.
Perhaps you might be willing to assist me??? Here is the scenario....
I want to run each driver (axis) within it's own cog, but I also want each of them to start movement simultaneously. I am very close to figuring it all out, but my cogs are dying (after the InitializePins method) and I know I need some sort of repeat loop to keep them alive, meanwhile updating some variables and having a trigger event. Basically I need to update (3) variables within a child object, while the child object is in a loop. Instead of continually checking the values for alteration, I will be using a WAITPEQ to inform the loop that the variables have been changed and start movement.
The attached code is a bit choppy, because it is a work in progress, but I think you will have a good understanding of what I am attempting and what is holding me back. As it stands now, the drivers function and the axes move, but not in parallel as intended. Like I said, I know it needs a repeat loop. Any suggestions???