' Linear regression (curve fitting)
' NOTE: it's not very accurate! Don't use for real world applications!

' https://www.codesansar.com/numerical-methods/linear-regression-method-using-c-programming.htm

If Info("wordsize") < 64 Then Print "This program requires a 64-bit uBasic" : End

Dim @x(16) : Dim @y(16)                ' I doubt you'll enter more..
x = Set(y, Set(z, Set(p, 0)))          ' x, y, xy, x2
                                       ' enter parameters
Do
  Input "How many data points? "; q
  Until (q<17) + (q>0)
Loop : Print

For i = 0 To q-1
  @x(i) = FUNC(_Fenter (Join("x[", Str(i), "] = ")))
  @y(i) = FUNC(_Fenter (Join("y[", Str(i), "] = ")))

  x = x + @x(i)                        ' process the data points right away
  p = p + FUNC(_Fmul (@x(i), @x(i)))
  y = y + @y(i)
  z = z + FUNC(_Fmul (@x(i), @y(i)))
Next                                   ' enter next data point

q = q * 16384                          ' we need a fractional value now
b = FUNC(_Fdiv(FUNC(_Fmul (q, z)) - FUNC(_Fmul (x, y)), FUNC(_Fmul (q, p)) - FUNC(_Fmul (x, x))))
a = FUNC(_Fdiv(y - FUNC(_Fmul (b, x)), q))
                                       ' print the result
Print : Print "Equation of best fit is: y = ";
Proc _Fprint (a)
Print " + ";
Proc _Fprint (b)
Print "x"
End

_Fmul Param (2) : Return ((a@*b@)/16384)
_Fdiv Param (2) : Return ((a@*16384)/b@)
_Ftoi Param (1) : Return ((10000*a@)/16384)
_Itof Param (1) : Return ((16384*a@)/10000)
_Fenter Param (1) : Return (FUNC(_Stof(Ask (a@))))
_Fprint Param (1) : a@ = FUNC(_Ftoi(a@)) : Print Using "+?.####";a@; : Return

_Stof                                  ' convert a string to a fraction
  Param (1)                            ' string to be converted
  Local (5)

  e@ = 0                               ' set accumulator to zero

  If Len(a@) = 0 Then Return (e@)      ' ok, let's return zero
  f@ = Peek(a@, 0) = Ord("-")          ' save sign

  For c@ = f@ To Len(a@)-1             ' get the integer part of number
    d@=Peek(a@, c@) - Ord("0")         ' convert to figure
  While (d@ > -1 ) * (d@ < 10)         ' stop when non-digit is found
    e@ = (e@*10) + d@                  ' add to accumulator
  Next                                 ' next digit

  If d@=Ord(".")-Ord("0") Then         ' if we found a decimal point
                                       ' parse the fraction
    For b@=c@+1 To Min(Len(a@)-1, c@+4)
      d@=Peek(a@, b@) - Ord("0")
    While (d@ > -1 ) * (d@ < 10)
      e@ = (e@*10) + d@                ' and add it to the accumulator
    Next
                                       ' compensate for missing digits
    For b@=Len(a@) To c@+4 : e@=e@*10 : Next
    e@=FUNC(_Itof(e@))                 ' convert to a fractional number

  Else
    e@=e@*16384                        ' convert to a fractional number
  EndIf

Return (e@ * (0-f@-f@+1))

