Can anyone do mathamatical magic?

Tyro

Member
I understand that picaxes can only handle positive integers from 0 to 65,535. Does anyone know of a mathematical sleight of hand that will allow me to find the reciprocal of a word and then multiply it to bring it back to a word once more?

For example; 1 / 20,000 = 0.00005
0.00005 x 1000 x 1000 = 50

It does not matter how many steps are involved, speed is not an issue.
 

cravenhaven

Senior Member
It would help if you would specify the range of numbers requiring processing (eg 1 to 20,000) and the accuracy required.
eg if you set a word equal to -1 and then divided that by your number that might be accurate enough.

eg
65535/20000=3.xxx =3 in integer maths.
 

westaust55

Moderator
Concur with Cravenhaven.

more information on the rnage for the numbers and required accuracy is required.
What exactly does "and then multiply it to bring it back to a word once more" mean?

In the example given, the result of "50" will be handled by a byte variable (0-255 range)

To take the OP's example

For example; 1 / 20,000 = 0.00005
0.00005 x 1000 x 1000 = 50

If instead, you multiply the numerator by 1000 and if you can divide the denominator by 1000 then:
1000 / 20 = 50

Say the divisor was to be 20500, there is nothing stopping the numerator being 10,000 to improve the accuracy. Even also only dividing the denominator by 100 (instead of 1000)

1 / 20,500 = 0.00004878
with 1000 / 20 = 50 we still have the same number is with the first number thus there is greater error.
However, if we using 10,000 / 205 the result with PICAXE math is "48"

Likewise for the denominator of 20250,
1 / 20,250 = 0.00004938
with PICAXE math 10,000 / 202 = 49
so results can be close but whether this is sufficient accuracy only the OP knows.
 

hippy

Ex-Staff (retired)
It would also be worth explaining what your project is as there may be other ways to achieve the result you want.
 

AllyCat

Senior Member
Hi,

Integer division produces a result plus a remainder, but you normally want to be able to ignore the remainder (except perhaps by rounding up the result by 1 when appropriate). Therefore, you need to scale up all your "small" integer values by a convenient multiplier. That might be 1000 or 10,000, but a multiplier of 65536 (10^16) can be very useful. Then you can form 32 bit numbers (two words) consisting of an integer word and a "fractional" word. There are several threads on this forum (not by me) concerning these "16+16 bit" mathematical calculations. Also, the PICaxe Basic ** operator can be very useful because it multiplies by the specified number and then effectively divides the result by 65536.

One you get the numbers in a suitably-scaled integer format, you might find my <30 byte code snippett, or the linked full 32-bit routines, of some use.

Cheers, Alan.
 

Tyro

Member
This project measures very small changes in capacitance. I do this by using an RC oscillator based on a TLC555. I count the number of pulses in one second and this number is the frequency. The period is proportional to the capacitance, it increases as the capacitance increases. The capacitance is inversely proportional to the frequency.

I am currently exporting the raw data, the frequency, and then manipulating it with Excel. I need every bit of resolution I can get. The frequency range is from 32,000Hz to 18,000Hz.

1 / 32000 = 0.00003125

I then multiply it by 1 million and get the result of 31.25. This is then manipulated further from a calibration table. I could also multiply it by 100 million to get an integer result of 3,125. Perhaps the second answer may be more useful for a Picaxe.
 

BESQUEUT

Senior Member
This project measures very small changes in capacitance. I do this by using an RC oscillator based on a TLC555. I count the number of pulses in one second and this number is the frequency. The period is proportional to the capacitance, it increases as the capacitance increases. The capacitance is inversely proportional to the frequency.

I am currently exporting the raw data, the frequency, and then manipulating it with Excel. I need every bit of resolution I can get. The frequency range is from 32,000Hz to 18,000Hz.

1 / 32000 = 0.00003125

I then multiply it by 1 million and get the result of 31.25. This is then manipulated further from a calibration table. I could also multiply it by 100 million to get an integer result of 3,125. Perhaps the second answer may be more useful for a Picaxe.
With my library, using this code :
Code:
      [color=Blue]for [/color][color=Purple]w20[/color][color=DarkCyan]=[/color][color=Navy]32000 [/color][color=Blue]to [/color][color=Navy]32010
            [/color][color=Blue]sertxd([/color][color=Navy]13[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Red]"1/"[/color][color=Black],#[/color][color=Purple]w20[/color][color=Black],[/color][color=Red]" = "[/color][color=Blue])
            [/color][color=Black]FL_Enter[/color][color=Blue]([/color][color=Navy]1[/color][color=Blue])
            [/color][color=Black]FL_Div[/color][color=Blue]([/color][color=Purple]W20[/color][color=Black],[/color][color=Navy]0[/color][color=Blue])
            gosub [/color][color=Black]FLsertxd10
      [/color][color=Blue]next [/color][color=Purple]w20
      [/color][color=Blue]low d.3
      sertxd([/color][color=Navy]13[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Red]"OK"[/color][color=Blue])[/color]
I have theses results :
Code:
1/32000 = 312496*10^-10
1/32001 = 312480*10^-10
1/32002 = 312480*10^-10
1/32003 = 312464*10^-10
1/32004 = 312464*10^-10
1/32005 = 312448*10^-10
1/32006 = 312448*10^-10
1/32007 = 312416*10^-10
1/32008 = 312416*10^-10
1/32009 = 312400*10^-10
1/32010 = 312400*10^-10
OK
 

BESQUEUT

Senior Member
Same but using 1*10^9/X (X variing from 32000 to 32010) :
Code:
      [color=Blue]for [/color][color=Purple]w20[/color][color=DarkCyan]=[/color][color=Navy]32000 [/color][color=Blue]to [/color][color=Navy]32010
            [/color][color=Blue]sertxd([/color][color=Navy]13[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Red]"1/"[/color][color=Black],#[/color][color=Purple]w20[/color][color=Black],[/color][color=Red]" = "[/color][color=Blue])
            [/color][color=Black]FL_EnterP10[/color][color=Blue]([/color][color=Navy]1[/color][color=Black],[/color][color=Navy]9[/color][color=Blue])        [/color][color=Green]' This is 1*10^9
            [/color][color=Black]FL_Div[/color][color=Blue]([/color][color=Purple]W20[/color][color=Black],[/color][color=Navy]0[/color][color=Blue])           [/color][color=Green]' this is w20*10^0=w20
            [/color][color=Blue]gosub [/color][color=Black]FLsertxd10
      [/color][color=Blue]next [/color][color=Purple]w20
      [/color][color=Blue]low d.3
      sertxd([/color][color=Navy]13[/color][color=Black],[/color][color=Navy]10[/color][color=Black],[/color][color=Red]"OK"[/color][color=Blue])[/color]
1/32000 = 31249.
1/32001 = 31249.
1/32002 = 31248.
1/32003 = 31247.
1/32004 = 31246.
1/32005 = 31245.
1/32006 = 31244.
1/32007 = 31243.
1/32008 = 31242.
1/32009 = 31241.
1/32010 = 31240.
OK
View attachment Floating_18_Frequency.bas
View attachment FL_JYB_U_002.bas
 

hippy

Ex-Staff (retired)
This project measures very small changes in capacitance. I do this by using an RC oscillator based on a TLC555. I count the number of pulses in one second and this number is the frequency. The period is proportional to the capacitance, it increases as the capacitance increases. The capacitance is inversely proportional to the frequency.
Thanks for the clarification; I suspected an "f=1/t" type problem.

Instead of using COUNT and having to calculate the reciprocal you may be able to use PULSIN to measure the length of the pulse you are getting, making that an easier calculation as the pulse period is the implied reciprocal of the frequency.
 

Tyro

Member
Thank you Besqueut and hippy. I think 'pulsin' will have too low a resolution and I did a cut and paste with the 'flenter10' code and got a syntax error. What device are you using and where is the subroutine 'FLsertxd10'?
I am snowed under but will work on it tomorrow.
 

BESQUEUT

Senior Member
Thank you Besqueut and hippy. I think 'pulsin' will have too low a resolution and I did a cut and paste with the 'flenter10' code and got a syntax error. What device are you using and where is the subroutine 'FLsertxd10'?
I am snowed under but will work on it tomorrow.
My library was tested with a 40X2 (both simulation and real Picaxe)
#8 and #9 codes are main program only.
You have to use complete programs :
Floating_18_Frequency.bas
FL_JYB_U_002.bas

or the Floating-Point-Math lib mentioned in #5. (tested with a 8M2 as said by Brewer)
 
Last edited:

BESQUEUT

Senior Member
Brewer lib test program :
Code:
[color=Blue]for [/color][color=Black]wfB [/color][color=DarkCyan]= [/color][color=Navy]32000 [/color][color=Blue]to [/color][color=Navy]32010
      [/color][color=Black]wfA [/color][color=DarkCyan]= [/color][color=Navy]1
      [/color][color=Black]bpA [/color][color=DarkCyan]= [/color][color=Navy]5
      [/color][color=Blue]sertxd ([/color][color=Red]"1/" [/color][color=Black],#wfB,[/color][color=Red]"="[/color][color=Blue])
      [/color][color=Black]bpB [/color][color=DarkCyan]= [/color][color=Navy]0
      [/color][color=Blue]gosub [/color][color=Black]fDivideAbyB
      [/color][color=Blue]gosub [/color][color=Black]fAssignCtoA
      [/color][color=Blue]gosub [/color][color=Black]fdisplayA
      [/color][color=Blue]sertxd([/color][color=Navy]13[/color][color=Black],[/color][color=Navy]10[/color][color=Blue])
next [/color][color=Black]wfB
      [/color][color=Blue]sertxd([/color][color=Red]"OK"[/color][color=Black],[/color][color=Navy]13[/color][color=Black],[/color][color=Navy]10[/color][color=Blue])
end[/color]
Results :
1/32000=31250e-4
1/32001=31249e-4
1/32002=31248e-4
1/32003=31247e-4
1/32004=31246e-4
1/32005=31245e-4
1/32006=31244e-4
1/32007=31243e-4
1/32008=31242e-4
1/32009=31241e-4
1/32010=31240e-4
OK

If you want to try yourself, use : View attachment FloatingPointMath_freq.bas
 

AllyCat

Senior Member
Hi,

Or, you can get (almost) the same result as in #9 with 75 bytes of program code and 7 bytes of RAM in an 08M2: ;)

Code:
#picaxe 08m2			; And most others 
#no_data

symbol NUMERATOR 	= 1000000000     		; Test Data = 10^9
symbol NUMERHI  	= NUMERATOR / $10000
symbol NUMERLO  	= NUMERATOR & $0FFFF

symbol numlo = w1				; Numerator Lo, Also Returns Result (max 16 bits)
symbol numhi = w2				; Numerator Hi, Returns Remainder
symbol divis = w3				; Divisor (max 15 bits), Unchanged on Return
symbol pass  = b0				; Loop counter

main:
   for divis = 32000 to 32010
      sertxd(cr,lf,"1 / ",#divis," = ")
      numhi = NUMERHI
      numlo = NUMERLO 
      call div31     
      sertxd(#numlo)
   next divis
   end

div31:						; Enter here to Divide with NO error check
   for pass =  0 to 15				; Repeat for each bit position
      numhi = numhi + numhi + bit31		; Start to shift numerator left (top bit lost)
      numlo = numlo + numlo    			; Shift low word	
      if numhi >= divis then 			; Skip if can't subtract
         numhi = numhi - divis   		; Subtract divisor and ...				
         numlo = numlo + 1			; Add the flag to result (in low word)
      endif		
   next pass
   return
Cheers, Alan.
 

Terry Smith

New Member
Hi Tyro,

I hope that this is not too late. I have just come across this thread and by coincidence I posted yesterday code that may overcome your problem in the Code Snippets section as: 32 Bit Unsigned Integer Calculations with 10 digit Decimal Output. You can get up to 8 decimal places for a reciprocal. I'm new here and don't know how to insert a link.

Terry Smith

EDIT:
Link to the mentioned thread:
http://www.picaxeforum.co.uk/showthread.php?28618-32-bit-unsigned-integer-calculations-with-10-digit-decimal-output-(with-code)
WA55
 
Last edited by a moderator:
Top