Basicprogramming(.org) > General questions and discussions

Power function

(1/2) > >>

B+:
what? Naalaa has no power (function)! well here is one that offers some rough estimates:

--- Code: ---
' Power pack the short version.txt
' written for Naalaa 6 by bplus posted 2018-07-23
' extracted from large test of fractions, random number functions, string... in Power test.txt

' The main purpose of this code: to demo a power function for real numbers,

' I had an idea for how real numbers to the power of real numbers might be done ie x# ^ y# = ?
' This means that not only can you take SQR of a number, you can get cube or cube root, quartic, 5th 6th... roots and any multiple

' It came from this simple idea
' 2 ^ 3.5 = 2 ^ 3 * 2 ^ .5 = 8 * Sqr(2)
' 3 ^ 3.5 = 3 ^ 3 * 3 ^ .5 = 27 * Sqr(3)

' so 2 ^ 3.25 = 2 ^ 3 * 2 ^ .25
' what is 2 ^ .25 ?  It is sqr(sqr(2)) !

' likewise 2 ^ 3.125 = 2 ^ 3 * 2 ^ 1/8
' what is 2 ^ 1/8 ? It is sqr(sqr(sqr(2))) !

' any decimal can be written as a sum of fraction powers of 2, as any integer can be written in powers of 2.
' in binary expansions
' 1/2 = .1       or .5 base 10
' 1/4 = .01      or .25 base 10
' 1/8 = .001     or .125 base 10
' 1/16 = .0001   or .0625 base 10

' So with binary expansion of decimal, we can SQR and multiply our way to an estimate
' of any real number to the power of another real number using binary expansion of
' the decimal parts as long as we stay in Naalaa integer limits and are mindful of precision.

constant:
wW 800
wH 720
hidden:
set window 100, 20, wW, wH

do
wln "And now for the main event! We test the power#(x#, pow#) function!"
write "(nothing) quits, Please enter a real (float) decimal number raise to some power. x# = "
x# = rln#()
if x# = 0.0 then break
write "(nothing) quits, Please enter a real (float) decimal power. pow# = "
pw# = rln#()
if pw# = 0.0 then break
result# = power#(x#, pw#)
wln result#, " is what we estimate for x# raised to power of pow#"
wln
loop
wln
wln "Far from precise of course, but this code is clear proof of concept!"
wln " OMG, it worked!!!"
wait keydown

' A power function for real numbers (small ones but still!)
' x# to the power of pow#
function power#(x#, pow#)
'this sub needs 2 other subs
'rite\$
'bExpand20\$

'this is going to follow covertReal2Fraction\$, first deal with integer part if any
r\$ = str\$(pow#)
s\$[] = split(r\$, ".")
integer\$ = s\$
build# = 1.0
if integer\$ <> "0"
p = int(integer\$)
for i = 1 to p
build# = build# * x#
next
endif
'that takes care of integer part,
'now for the fraction part convert decimal to fraction
n\$ = s\$
ld = len(n\$)
while rite\$(n\$, 1) = "0"
n\$ = left\$(n\$, ld - 1)
ld = len(n\$)
wend
denom = 10
for i = 2 to ld
denom = denom * 10
next
numer = int(n\$)
'OK for bExpand20\$ don't have to simplify and that saves us having to extract n and d again from n/d
bs\$ = bExpand20\$(numer, denom)
'at moment we haven't taken any sqr of x
runningXSQR# = x#
'run through all the 0's and 1's in the bianry expansion of the fraction part of the power float
for i = 1 to len(bs\$)
'this is the matching sqr of the sqr of the sqr... of x#
runningXSQR# = sqr#(runningXSQR#)
'for every 1 in the expansion, multiple our build with the running sqr of ... sqr of x
if mid\$(bs\$, i - 1, 1) = "1" then build# = build# * runningXSQR#
next
'our build# should be a estimate or x# to power of pow#
return build#
endfunc

'write a series of 1s and 0s that represent the decimal fraction n/d in binary 20 places long
function bExpand20\$(nOver, d)
' b for base
b# = 0.5
' r for remainder
r# = float(nOver)/float(d)
' s for string\$ 0's and 1's that we will build and return for function value
s\$ = ""
' f for flag to stop
f = 0
' c for count to track how far we are, don't want to go past 20
c = 0
while f = 0
if r# < b#
s\$ = s\$ + "0"
else
s\$ = s\$ + "1"
if r# > b#
r# = r# - b#
else
f = 1
endif
endif
c = c + 1
if c >= 20 then f = 1
b# = b# * 0.5
wend
return s\$
endfunc

'not right\$
function rite\$(stringy\$, amount)
return mid\$(stringy\$, len(stringy\$) - amount, amount)
endfunc

--- End code ---

B+:
Oh apparently Naalaa does have a power function pow#(a#, b#) a closely kept secret I guess.

Here is why I thought it didn't have a power function (plus the keyword does not highlight when typed because I tried that before rolling my own):

B+:
Wow in QB64, this power estimator is on par with the ^ operator!

--- Code: ---_TITLE "Power Function 2 by bplus"
'QB64 X 64 version 1.2 20180228/86  from git b301f92

' started 2018-07-23  Naalaa has no power function (or operator), so I wrote a power function for it.
' ''Power pack the short version.txt
' ''written for Naalaa 6 by bplus posted 2018-07-23
' ''extracted from large test of fractions, random number functions, string... in Power test.txt
' 2018-07-24 Power Function 2 split is replaced with two much smaller and very handy string functions.

' OMG the crazy thing worked! It produced decent estimates of roots given the limitations of precision...
' Now I want to see how well it works with far greater precision available. So here we are, looking to see
' how this function compares to the regualar ^ operator in QB64.

' The main purpose of this code: to demo a power function for real numbers,

' I had an idea for how real numbers to the power of real numbers might be done ie x ^ y = ?
' This means that not only can you take SQR of a number, you can get cube or cube root, quartic, 5th 6th... roots and any multiple

' It came from this simple idea
' 2 ^ 3.5 = 2 ^ 3 * 2 ^ .5 = 8 * Sqr(2)
' 3 ^ 3.5 = 3 ^ 3 * 3 ^ .5 = 27 * Sqr(3)

' so 2 ^ 3.25 = 2 ^ 3 * 2 ^ .25
' what is 2 ^ .25 ?  It is sqr(sqr(2)) !

' likewise 2 ^ 3.125 = 2 ^ 3 * 2 ^ 1/8
' what is 2 ^ 1/8 ? It is sqr(sqr(sqr(2))) !

' any decimal can be written as a sum of fraction powers of 2 ie 1/2^n, as any integer can be written in powers of 2.
' in binary expansions
' 1/2 = .1       or .5 base 10
' 1/4 = .01      or .25 base 10
' 1/8 = .001     or .125 base 10
' 1/16 = .0001   or .0625 base 10

' So with binary expansion of decimal, we can SQR and multiply our way to an estimate
' of any real number to the power of another real number using binary expansion of
' the decimal parts as long as we stay in Naalaa integer limits and are mindful of precision.

CONST wW = 800
CONST wH = 600
SCREEN _NEWIMAGE(wW, wH, 32)
_SCREENMOVE 360, 60
_DEFINE A-Z AS _FLOAT

DO
PRINT "Testing the power(x, pow) function:"
INPUT "(nothing) quits, Please enter a real number to raise to some power. x = "; x
IF x = 0 THEN EXIT DO
INPUT "(nothing) quits, Please enter a real number for the power. pow = ", pw
IF pw = 0 THEN EXIT DO
result = power(x, pw)
PRINT result; " is what we estimate for"; x; " raised to power of"; pw
PRINT x ^ pw; " is what the ^ operator gives us."
PRINT
LOOP
PRINT
PRINT "This is matching the ^ operator very well! This code is clear proof of concept!"
PRINT " OMG, it worked!!!"
SLEEP

' A power function for real numbers (small ones but still!)
' x to the power of pow
FUNCTION power## (x AS _FLOAT, pow AS _FLOAT)
'this sub needs: bExpand60\$, leftOf\$, rightOf\$

DIM build AS _FLOAT
r\$ = "0" + STR\$(pow) 'in case pow starts with decimal
integer\$ = leftOf\$(r\$, ".")
build = 1.0
IF integer\$ <> "0" THEN
p = VAL(integer\$)
FOR i = 1 TO p
build = build * x
NEXT
END IF
'that takes care of integer part

n\$ = rightOf\$(r\$, ".")
IF n\$ = "" THEN power = build: EXIT SUB

'remove 0's to right of main digits
ld = LEN(n\$)
WHILE RIGHT\$(n\$, 1) = "0"
n\$ = LEFT\$(n\$, ld - 1)
ld = LEN(n\$)
WEND

'note: we are pretending that the ^ operator is not available, so this is hand made integer power
denom& = 10
FOR i = 2 TO ld
denom& = denom& * 10
NEXT

'OK for bExpand60\$ don't have to simplify fraction and that saves us having to extract n and d again from n/d
bs\$ = bExpand60\$(VAL(n\$), denom&)

'at moment we haven't taken any sqr of x
runningXSQR = x

'run through all the 0's and 1's in the bianry expansion, bs\$, the fraction part of the power float
FOR i = 1 TO LEN(bs\$)
'this is the matching sqr of the sqr of the sqr... of x
runningXSQR = SQR(runningXSQR)
'for every 1 in the expansion, multiple our build with the running sqr of ... sqr of x
IF MID\$(bs\$, i, 1) = "1" THEN build = build * runningXSQR
NEXT

'our build should now be an estimate or x to power of pow
power = build
END FUNCTION

'write a series of 1s and 0s that represent the decimal fraction n/d in binary 60 places long
FUNCTION bExpand60\$ (nOver&, d&)
DIM b AS _FLOAT, r AS _FLOAT
' b for base
b = 0.5
' r for remainder
r = nOver& / d&
' s for string\$ 0's and 1's that we will build and return for function value
s\$ = ""
' f for flag to stop
f% = 0
' c for count to track how far we are, don't want to go past 20
c% = 0
WHILE f% = 0
IF r < b THEN
s\$ = s\$ + "0"
ELSE
s\$ = s\$ + "1"
IF r > b THEN
r = r - b
ELSE
f% = 1
END IF
END IF
c% = c% + 1
IF c% >= 60 THEN f% = 1
b = b * 0.5
WEND
bExpand60\$ = s\$
END FUNCTION

FUNCTION leftOf\$ (source\$, of\$)
posOf = INSTR(source\$, of\$)
IF posOf > 0 THEN leftOf\$ = MID\$(source\$, 1, posOf - 1)
END FUNCTION

FUNCTION rightOf\$ (source\$, of\$)
posOf = INSTR(source\$, of\$)
IF posOf > 0 THEN rightOf\$ = MID\$(source\$, posOf + LEN(of\$))
END FUNCTION

--- End code ---

ScriptBasic:

--- Quote ---' It came from this simple idea
' 2 ^ 3.5 = 2 ^ 3 * 2 ^ .5 = 8 * Sqr(2)
' 3 ^ 3.5 = 3 ^ 3 * 3 ^ .5 = 27 * Sqr(3)

--- End quote ---

Good luck finding a language that allows the results to be an expression rather than a variable.

B+:

--- Quote from: John on July 27, 2018, 04:18:36 am ---
--- Quote ---' It came from this simple idea
' 2 ^ 3.5 = 2 ^ 3 * 2 ^ .5 = 8 * Sqr(2)
' 3 ^ 3.5 = 3 ^ 3 * 3 ^ .5 = 27 * Sqr(3)

--- End quote ---

Good luck finding a language that allows the results to be an expression rather than a variable.

--- End quote ---

Hi John,

The point of those 2 little examples was to show that 2 ^ 3.5 for instance can be calculated without the ^ operator.
The SQR(2) part of course is further evaluated down to a single value. 8 * 1.4142.. = 11.3137...

x to an integer power like x ^ n  where n is positive integer (and not real number with decimals) is easy peasy without ^

p = 1
for i = 1 to n
p = p * x
next

result: p = x ^ n when n is positive integer

Integer powers are easy to do without the ^ operator but how can we do a power that is a real number (AKA float or decimal) (and positive).

This became the first most crude estimate for x ^ power for the return value of function for the integer part only.

For the decimal part of the power, I took it as a fraction .75 = 75/100
and expanded that fraction to binary 1's and 0's.

Then I ran down the expansion a 0 or 1 at a time, keeping a running value of the sqr(sqr... (sqr(x))) for each step.
If the expansion had a 1 in it, then the return result was multiplied by that running value.
Such that by the time you reach the end of the expansion, you have a very decent estimate of x ^ power without using the ^.

From the time BASIC started using the ^ operator there had to be a way to calculate that expression because of course you can't use ^ to calculate an expression using the ^ operator. I don't know if this is the way it was done but it is the way it could have been done if the SQR() function was available.