_TITLE "Math regulator mr" ' b+ start 2020-08-17 ' 2020-08-16 picking up from String Math add$(), subtr$(), mult$() onto divide$()
' I always wanted to try doing division by multipling the numerator
' by the multiplicative inverse of denominator.
' n/d = n * 1/d so how bout a function that does 1/n.
' Then divide$() is pretty easy with mult$ Yes works but need more decimal work.
' 2020-08-17 redo all this with a decimal point for nInverse just start outstr with "." instead ""
' Now somethings off with divide$() first is 1 / 500 should be .002 returning .2, debug."
' Much better than post of last night
' showDP rounds up to DP (Decimal Places IF there are more decimals past DP)
' 2020-08-17 Math regulator mr$(a$, ops$, b$) ' manages before and after calls to 4 basic arith operations
' note: 265 lines with just the set of functions so far
' 2020-08-18 last night subtr and signs confused hell out of me but I think I have all code I need for +!
' OK add and subtr seem to be working with signs and decimals but ugly code, can we combine lines?
' OH yeah, traded 12 redundant lines for 2! and a bunch of debug and other 389 lines to 354
' OK setup for * and /, mr$ finished adding 77 lines of code
' OK everything is simple after divide$() and substraction with signs and decimals ;-))
' debug tests
'PRINT "2105 ? "
'PRINT mr$("5", "+", "2100") ' OK
'PRINT "-10039.0965 ? "
'PRINT mr$("6.1035", "+", "-10045.2") ' OK
'PRINT "-801.99968 ?"
'PRINT mr$("-802", "+", ".00032")
'PRINT "-.0003500009 ?"
'PRINT mr$("-.00035", "+", "-.0000000009")
'PRINT "-5 ?"
'PRINT mr$("-10", "-", "-5")
'PRINT "-15 ?"
'PRINT mr$("-10", "-", "5") 'X fixed
'PRINT "15 ?"
'PRINT mr$("10", "-", "-5")
'PRINT "5 ?"
'PRINT mr$("10", "-", "5")
'PRINT "4.99 ?"
'PRINT mr$("-.010", "-", "-5")
'PRINT "-5.01 ?"
'PRINT mr$("-.010", "-", "5") 'X fixed
'PRINT "5.01 ?"
'PRINT mr$(".010", "-", "-5")
'PRINT "-4.99 ?"
'PRINT mr$(".010", "-", "5")
'PRINT .00207 * 10000; "?"
'PRINT mr$(".00207", " * ", "10000") 'OK
'PRINT 2468.02468 / .02; "?"
'PRINT mr$("2468.02468", "/", ".02") 'OK
'PRINT -.333333333333333333 * -3.00000000000; "?"
'PRINT mr$("-.333333333333333333", "*", "-3.00000000000") 'OK
'PRINT -1.0000001 / .07; "?"
'PRINT mr$("-1.0000001", "/", ".07") 'OK
'PRINT 90.9 / -30; "?"
'PRINT mr$("90.9", "/", "-30") 'OK
'random testing for correct signs, decimal places and values
DIM op$
, a$
, b$
, mrStr$
, ma$
, mb$
, qbCalc$
'pick two numbers
ma$ = "-": ma = -1
ma$ = "": ma = 1
mb$ = "-": mb = -1
mb$ = "": mb = 1
ad
= ma
* RND * 10 ^ ea: bd
= mb
* RND * 10 ^ eb
CASE "+": check
= ad
+ bd
CASE "-": check
= ad
- bd
CASE "*": check
= ad
* bd
CASE "/": check
= ad
/ bd
PRINT a$;
" "; op$;
" "; b$;
" =" mrStr$ = mr$(a$, op$, b$)
PRINT mrStr$;
" according to mr$ function we are testing." PRINT qbCalc$;
" according to QB64 math" PRINT "Next subtr$ check in 10 secs, or press key, press escape to quit..." SLEEP 10 ' comment out to see if any delay in execution of print
FUNCTION mr$
(a$
, op$
, b$
) ' catchy? mr$ for math regulator DIM ca$
, cb$
, aSgn$
, bSgn$
, postOp$
, sgn$
op$
= _TRIM$(op$
) 'save fixing each time ca$
= _TRIM$(a$
): cb$
= _TRIM$(b$
) 'make copies in case we change 'strip signs and decimals
aSgn$
= "-": ca$
= MID$(ca$
, 2) aSgn$ = "": ca$ = ca$
ca$
= MID$(ca$
, 1, dp
- 1) + MID$(ca$
, dp
+ 1) adp = 0
bSgn$
= "-": cb$
= MID$(cb$
, 2) bSgn$ = "": cb$ = cb$
cb$
= MID$(cb$
, 1, dp
- 1) + MID$(cb$
, dp
+ 1) bdp = 0
IF op$
= "+" OR op$
= "-" OR op$
= "/" THEN 'add or subtr even up strings on right of decimal 'even up the right sides of decimals if any
dp = adp + bdp
'now according to signs and op$ call add$ or subtr$
IF aSgn$
= bSgn$
THEN 'really add postOp$ = aSgn$ + add$(ca$, cb$)
ELSE 'have a case of subtraction IF aSgn$
= "-" THEN postOp$
= subtr$
(cb$
, ca$
) ELSE postOp$
= subtr$
(ca$
, cb$
) IF bSgn$
= "-" THEN 'really add but switch b sign bSgn$ = ""
postOp$ = subtr$(cb$, ca$)
postOp$ = add$(ca$, cb$)
bSgn$ = "-"
postOp$ = aSgn$ + add$(ca$, cb$)
postOp$ = subtr$(ca$, cb$)
postOp$
= sgn$
+ mult$
(ca$
, cb$
) postOp$
= sgn$
+ divide$
(ca$
, cb$
) 'put dp back
lpop
= LEN(postOp$
) ' put decimal back postOp$
= MID$(postOp$
, 1, lpop
- dp
) + "." + MID$(postOp$
, lpop
- dp
+ 1) mr$ = trim0$(postOp$)
di$
= MID$(nInverse$
(d$
, 100), 2) 'chop off decimal point after ndi$ = mult$(n$, di$)
divide$ = trim0$(ndi$)
FUNCTION nInverse$
(n$
, DP
AS INTEGER) 'assume decimal at very start of the string of digits returned, no rounding DIM m$
(1 TO 9), si$
, r$
, outstr$
, d$
m$(i) = mult$(si$, n$)
outstr$ = ""
outstr$ = "." 'everything else n > 1 is decimal 8/17
r$ = "10"
outstr$ = outstr$ + "0" ' add 0 to the output string
r$ = r$ + "0"
outstr$ = outstr$ + d$
r$ = subtr$(r$, mult$(d$, n$)) 'r = r -d*n
r$ = r$ + "0" 'add another place
FUNCTION mult$
(a$
, b$
) 'assume both positive integers prechecked as all digits strings DIM f18$
, f1$
, t$
, build$
, accum$
'find the longer number and make it a mult of 18 to take 18 digits at a time from it
f1$ = b$
f1$ = a$
FOR dp
= LEN(f1$
) TO 1 STEP -1 'dp = digit position of the f1$ build$ = "" 'line builder
co = 0
'now taking 18 digits at a time Thanks Steve McNeill
v18
= VAL(MID$(f18$
, m
* 18 - g
* 18 + 1, 18)) build$
= MID$(t$
, 2) + build$
accum$ = build$
accum$
= add$
(accum$
, build$
+ STRING$(LEN(f1$
) - dp
, "0")) mult$ = accum$
FUNCTION subtr$
(sum$
, minus$
) ' assume both numbers are positive all digits DIM ts$
, tm$
, sign$
, LG$
, sm$
, t$
, result$
ts$ = TrimLead0$(sum$): tm$ = TrimLead0$(minus$)
IF trim0
(ts$
) = trim0$
(tm$
) THEN subtr$
= "0":
EXIT FUNCTION 'OK proceed with function knowing they are not equal tenE18 = 1000000000000000000 'yes!!! no dang E's
IF LTE
(ts$
, tm$
) THEN ' which is bigger? minus is bigger sign$ = "-"
sign$ = ""
'now taking 18 digits at a time From Steve I learned we can do more than 1 digit at a time
VB
= VAL(MID$(LG$
, m
* 18 - g
* 18 + 1, 18)) vs
= VAL(MID$(sm$
, m
* 18 - g
* 18 + 1, 18)) p = (m - g) * 18
p = p - 1
result$ = t$ + result$
subtr$ = sign$ + result$
FUNCTION add$
(a$
, b$
) 'add 2 positive integers assume a and b are just numbers no spaces or - signs 'first thing is to set a and b numbers to same length and multiple of 18 so can take 18 digits at a time
DIM fa$
, fb$
, t$
, new$
, result$
'now taking 18 digits at a time Thanks Steve McNeill
sa
= VAL(MID$(fa$
, m
* 18 - g
* 18 + 1, 18)) sb
= VAL(MID$(fb$
, m
* 18 - g
* 18 + 1, 18)) result$ = new$ + result$
add$ = result$
' String Math Helpers -----------------------------------------------
'this function needs TrimLead0$(s$)
FUNCTION LTE
(a$
, b$
) ' a$ Less Than or Equal b$ comparison of 2 strings ca$ = TrimLead0$(a$): cb$ = TrimLead0(b$)
LTE = -1
LTE = -1
LTE = 0
' ------------------------------------- use these for final display
FUNCTION TrimLead0$
(s$
) 'for treating strings as number (pos integers) copys$
= _TRIM$(s$
) 'might as well remove spaces too i = 1: find = 0
i = i + 1: find = 1
IF copys$
= "" THEN TrimLead0$
= "0" ELSE TrimLead0$
= copys$
copys$
= _TRIM$(s$
) 'might as well remove spaces too TrimTail0$ = copys$
i
= LEN(copys$
): find
= 0 i = i - 1: find = 1
TrimTail0$
= MID$(copys$
, 1, dp
- 1) TrimTail0$
= MID$(copys$
, 1, i
)
cs$ = s$
cs$ = TrimLead0$(cs$)
cs$ = TrimTail0$(cs$)
IF si$
= "-" THEN trim0$
= si$
+ cs$
ELSE trim0$
= cs$
' for displaying truncated numbers say to 60 digits
cNum$ = num$ 'since num$ could get changed
showDP$ = num$
d
= VAL(MID$(cNum$
, dp
+ nDP
+ 1, 1)) cNum$ = "0" + cNum$ ' tack on another 0 just in case 9's all the way to left
dp = dp + 1
i = dp + nDP
i = i - 1
cNum$
= MID$(cNum$
, 1, dp
+ nDP
) 'chop it showDP$ = trim0$(cNum$)
showDP$
= MID$(cNum$
, 1, dp
+ nDP
)