nullschritt

Problem Storing Arrays Inside Arrays

31 posts in this topic

Hello guys, I have a matrix inverse function that I am trying to improve the accuracy of by making it preform math on fractions instead of floats, however is appears I'm having issues accessing an array embedded inside a 2D array ($array[1][1][0]) where [0] would contain a 1D array with 2 values in it.

See my code below, and as always thanks a ton! (you will need the fractions UDF '?do=embed' frameborder='0' data-embedContent>>)

#include "fractions.au3"
#include <array.au3>

$matricies = _loaddata(_datagen())

_inv_big($matricies[0])

Func _inv_big($m)
        Local $n = UBound($m, 1)
        Local $a[$n][2 * $n]
        Local $inv[$n][$n]
        Local $temprow[2 * $n]
        Local $pivelt, $tarelt, $pivrow, $tarrow, $k, $i, $j
        #Region - Filling matrix A
            For $i = 0 To $n - 1
                For $j = 0 To $n - 1
                    $a[$i][$j] = $m[$i][$j]
                Next
            Next
            For $i = 0 To $n - 1
                $a[$i][$n + $i] = 1
            Next
        #EndRegion - Filling matrix A
        #Region - Inverting matrix $M
            For $pivrow = 0 To $n - 1
                $pivelt = $a[$pivrow][$pivrow]
                If ($pivelt == 0) Then
                    $k = $pivrow + 1
                    While ($pivelt == 0 AND $k <= $n)
                        $pivelt = $a[$k][$pivrow]
                        $k = $k + 1
                    WEnd
                    If ($pivelt == 0) Then
                        SetError(1)
                        Return
                    Else
                        For $i = 0 To 2 * $n - 1
                            $temprow[$pivrow][$i] = $a[$pivrow][$i]
                            $k = $k - 1
                        Next
                        For $i = 0 To 2 * $n - 1
                            $a[$pivrow][$i] = $a[$k][$i]
                        Next
                        For $i = 0 To 2 * $n - 1
                            $a[$k][$i] = $temprow[$k][$i]
                        Next
                    EndIf
                EndIf
                For $i = 0 To 2 * $n - 1
                    $a[$pivrow][$i] = _fraction(Number($a[$pivrow][$i]), Number($pivelt))
                    ;array is accessable here
                Next
                #Region - replace all other rows by target
                    For $tarrow = 0 To $n - 1
                        If ($tarrow <> $pivrow) Then
                            $tarelt = $a[$tarrow][$pivrow]
                            For $i = 0 To 2 * $n - 1
                                $a[$tarrow][$i] = _FractionSubtract(_fraction(number($a[$tarrow][$i])), _FractionMultiply($a[$pivrow][$i], _fraction(number($tarelt))))
                                _ArrayDisplay($a[$tarrow][$i])
                                ;array is accessable here via _arraydisplay() but when I try to consolewrite the values it says the dimension range is exceeded
                                ConsoleWrite($a[$tarrow][$i][0]&'/'&$a[$tarrow][$i][1]&@CRLF)
                                
                            Next
                         EndIf
                      Next
                      ;array is accessable here with _arraydisplay but still not via any other method
                #EndRegion - Now replace all other rows by target row minus pivot row times element in target row and pivot colum
             Next
                _ArrayDisplay($a)
             ;array is nullified, all values for the array get set to 1
            #Region - finally extract the inverse from columns N+1 to 2N
                For $i = 0 To $n - 1
                    For $j = 0 To $n - 1
                        $inv[$i][$j] = $a[$i][$n + $j]
                    Next
                Next
            #EndRegion - finally extract the inverse from columns N+1 to 2N
            Return $inv
        #EndRegion - Inverting matrix $M
     EndFunc

     Func _datagen()
        Local $ret
        For $i = 1 To 112
            Local $data = ""
            For $x = 0 To 7
                For $y = 0 To 7
                    $data &= Random(111111111, 99999999999, 1) & ","
                Next
                $data = StringTrimRight($data, 1) & "/"
            Next
            $ret &= StringTrimRight($data, 1) & "|"
        Next
        Return $ret
     EndFunc

    Func _loaddata($data, $z = 112)
        Local $dataz[$z]
        $array = StringSplit($data, "|")
        If $array[0] < $z - 1 Then Return 0
        For $i = 0 To $z - 1
            $dataz[$i] = _stringtoarray($data, $i)
            If $dataz[$i] = 0 Then
                Return 0
            EndIf
        Next
        Return $dataz
    EndFunc

    Func _stringtoarray($data, $n = 0)
        $array = StringSplit($data, "|", 2)
        $next = StringSplit($array[$n], "/")
        $num2 = StringSplit($next[1], ",")
        Local $ar1[$next[0]][$num2[0]]
        For $i2 = 1 To $next[0]
            $next2 = StringSplit($next[$i2], ",", 2)
            For $i3 = 0 To UBound($next2) - 1
                If $i2 - 1 > $next[0] - 1 OR $i3 > $num2[0] - 1 OR $i3 > UBound($next2) Then
                    Return 0
                EndIf
                $ar1[$i2 - 1][$i3] = $next2[$i3]
            Next
        Next
        Return $ar1
    EndFunc

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

$array[1][1][0]  is for a 3D array

Try this :  ($array[1][1])[0]

Edit

I mean

ConsoleWrite(($a[$tarrow][$i])[0]&'/'&($a[$tarrow][$i])[1]&@CRLF)
Edited by mikell

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Yes using a 3D array is simpler than my suggestion here:

Either way is good, and mikell's way is also good, if you do decide to store arrays inside another. So much choice! :) I woulld use a 3D array: new example posted in the link.

Edited by czardas

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

 

$array[1][1][0]  is for a 3D array

Try this :  ($array[1][1])[0]

Edit

I mean

ConsoleWrite(($a[$tarrow][$i])[0]&'/'&($a[$tarrow][$i])[1]&@CRLF)

This works great for consolewrite() but when I try the below to turn the array into a string I get the error " Subscript used on non-accessible variable.:"

$a[$tarrow][$i] = ($a[$tarrow][$i])[0]&'/'&($a[$tarrow][$i])[1]

I'm trying to store the array inside the array as a string, so it's not an array inside an array.

Edited by nullschritt

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Yes using a 3D array is simpler than my suggestion here:

Either way is good, and mikell's way is also good, if you do decide to store arrays inside another. So much choice! :) I woulld use a 3D array: new example posted in the link.

 

I don't see adding an extra dimension to my array affecting my problem at all(but this could just be because I'm not understanding how it would be implemented in my function). I have a 2D array, that has to remain a 2D array, but each of the values in the 2D array needs to be a fraction.

Edited by nullschritt

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

The 3D array is just two arrays joined together. See my other suggestion - use 2x 2D arrays. One to store the dividends and the other to store the divisors; or use the syntax suggested by mikell. You can't view a 3D array using _ArrayDisplay(). Storing as strings was my first example in the other post. You will need to format the numbers as shown if you want to multiply the fractions later. That's not efficient.

I'll take another look tomorrow if you are still struggling by then. I have to sleep shortly. ;)

Edited by czardas

Share this post


Link to post
Share on other sites

The 3D array is just two arrays joined together. See my other suggestion - use 2x 2D arrays. One to store the dividends and the other to store the divisors; or use the syntax suggested by mikell. You can't view a 3D array using _ArrayDisplay(). Storing as strings was my first example in the other post. You will need to format the numbers as shown if you want to multiply the fractions later. That's not efficient.

I'll take another look tomorrow if you are still struggling by then. I have to sleep shortly. ;)

 

Thanks, I'm still just not sure how to implement a 3d array within my function, I understand what you're saying though, about the function being able to support fractions 100% without reformatting the output strings back into arrays.

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

My best guess would be that after the _fractionsubtract is done $a goes from a 2d to 3d array. I'd say save the 3d array values to a $temp and redim $a the send the values back.

Idk it very confusing. I'm trying to wrap my mind around it. Ya bc once 2D array $a goes to the _fractionsubtract all values return with an extra dimension and your basically trying to go like this $a [0][1]=$a [0][1][2]....

Maybe don't need redim if you try something like

$temp = _FractionSubtract(_fraction(number($a[$tarrow][$i])), _FractionMultiply($a[$pivrow][$i], _fraction(number($tarelt))))

$a[$tarrow][$i] = $temp[0] &'/'& $temp[1]

Edited by markyrocks

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

I took a look now and I still find this script rather confusing. The array variables have to be accessed correctly as shown. However the numbers are large and the types of calculation are introducing approximations. Depending on how many times approximations occur, the results may become less accurate than if you were to use floats. The test I did in the official thread only remained accurate for 29 iterations. Once there was about 20 or more accumilated approximations, the 15 digits returned using floats was more accurate than the value returned using fractions. This can actually be fixed.

Combining the Fraction UDF with large random numbers is not recommended. For example: pounds shillings and pence; or stones, pounds and ounces will remain accurate because imperial systems use measurements that are easy to divide, although such calibrations may seem an odd choice historically. The values are not likely to go out of range and these functions may be ideally suited in situations like that. Size limitations were my first thought when looking at your code earlier, otherwise I would have suggested using this UDF myself.

Your code contains more bugs, because at one point Fraction returns an error causing the code to terminate abruptly. You need to check for errors with code like this.

;

#include "fraction.au3"
#include <array.au3>

$matricies = _loaddata(_datagen())

_inv_big($matricies[0])

Func _inv_big($m)
    Local $n = UBound($m, 1)
    Local $a[$n][2 * $n]
    Local $inv[$n][$n]
    Local $temprow[2 * $n]
    Local $pivelt, $tarelt, $pivrow, $tarrow, $k, $i, $j
    #Region - Filling matrix A
    For $i = 0 To $n - 1
        For $j = 0 To $n - 1
            $a[$i][$j] = $m[$i][$j]
        Next
    Next
    For $i = 0 To $n - 1
        $a[$i][$n + $i] = 1
    Next
    #EndRegion - Filling matrix A
    #Region - Inverting matrix $M

    Local $aExpression = 0
    Local $iExtended = 0

    For $pivrow = 0 To $n - 1
        $pivelt = $a[$pivrow][$pivrow]
        If ($pivelt == 0) Then
            $k = $pivrow + 1
            While ($pivelt == 0 And $k <= $n)
                $pivelt = $a[$k][$pivrow]
                $k = $k + 1
            WEnd
            If ($pivelt == 0) Then
                SetError(1)
                Return
            Else
                For $i = 0 To 2 * $n - 1
                    $temprow[$pivrow][$i] = $a[$pivrow][$i]
                    $k = $k - 1
                Next
                For $i = 0 To 2 * $n - 1
                    $a[$pivrow][$i] = $a[$k][$i]
                Next
                For $i = 0 To 2 * $n - 1
                    $a[$k][$i] = $temprow[$k][$i]
                Next
            EndIf
        EndIf
        For $i = 0 To 2 * $n - 1
            $a[$pivrow][$i] = _fraction(Number($a[$pivrow][$i]), Number($pivelt))

            If @error Then ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ERROR<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


                MsgBox(0, "", "ERROR" & @CRLF & (@error = 2) ? "You cannot divide by zero!" : "???")
                Exit
            EndIf

            ;array is accessable here
        Next
        #Region - replace all other rows by target
        For $tarrow = 0 To $n - 1
            If ($tarrow <> $pivrow) Then
                $tarelt = $a[$tarrow][$pivrow]
                For $i = 0 To 2 * $n - 1
                    $aExpression = _FractionMultiply($a[$pivrow][$i], _fraction(Number($tarelt)))
                    ;If @error Then MsgBox(0, "", "ERROR = " & @error)
                    If @extended Then $iExtended += 1 ; Approximation used
                    $a[$tarrow][$i] = _FractionSubtract(_fraction(Number($a[$tarrow][$i])), $aExpression)
                    If @extended Then $iExtended += 1 ; Approximation used
                    ;If @error Then MsgBox(0, "", "ERROR = " & @error)
                    ;_ArrayDisplay($a[$tarrow][$i])
                    ;array is accessable here via _arraydisplay() but when I try to consolewrite the values it says the dimension range is exceeded
                    ConsoleWrite(($a[$tarrow][$i])[0] & '/' & ($a[$tarrow][$i])[1] & " - Approximations = " & $iExtended & @CRLF)
                    $iExtended = 0
                Next
            EndIf
        Next
        ;array is accessable here with _arraydisplay but still not via any other method
        #EndRegion - replace all other rows by target
    Next
    _ArrayDisplay($a)
    ;array is nullified, all values for the array get set to 1
    #Region - finally extract the inverse from columns N+1 to 2N
    For $i = 0 To $n - 1
        For $j = 0 To $n - 1
            $inv[$i][$j] = $a[$i][$n + $j]
        Next
    Next
    #EndRegion - finally extract the inverse from columns N+1 to 2N
    Return $inv
    #EndRegion - Inverting matrix $M
EndFunc   ;==>_inv_big

Func _datagen()
    Local $ret
    For $i = 1 To 112
        Local $data = ""
        For $x = 0 To 7
            For $y = 0 To 7
                $data &= Random(111111111, 99999999999, 1) & ","
            Next
            $data = StringTrimRight($data, 1) & "/"
        Next
        $ret &= StringTrimRight($data, 1) & "|"
    Next
    Return $ret
EndFunc   ;==>_datagen

Func _loaddata($data, $z = 112)
    Local $dataz[$z]
    $array = StringSplit($data, "|")
    If $array[0] < $z - 1 Then Return 0
    For $i = 0 To $z - 1
        $dataz[$i] = _stringtoarray($data, $i)
        If $dataz[$i] = 0 Then
            Return 0
        EndIf
    Next
    Return $dataz
EndFunc   ;==>_loaddata

Func _stringtoarray($data, $n = 0)
    $array = StringSplit($data, "|", 2)
    $next = StringSplit($array[$n], "/")
    $num2 = StringSplit($next[1], ",")
    Local $ar1[$next[0]][$num2[0]]
    For $i2 = 1 To $next[0]
        $next2 = StringSplit($next[$i2], ",", 2)
        For $i3 = 0 To UBound($next2) - 1
            If $i2 - 1 > $next[0] - 1 Or $i3 > $num2[0] - 1 Or $i3 > UBound($next2) Then
                Return 0
            EndIf
            $ar1[$i2 - 1][$i3] = $next2[$i3]
        Next
    Next
    Return $ar1
EndFunc   ;==>_stringtoarray

;

Console output before the crash:

0/1 - Approximations = 0
-380359654586940/446927 - Approximations = 1
171968865510555/287359 - Approximations = 2
-30656635528634/72801 - Approximations = 1
-8477385642562/23011 - Approximations = 1
636068037372/17107 - Approximations = 1
-156304644584205/150437 - Approximations = 1
-150536495218099/127802 - Approximations = 1
-1125373156/851252925 - Approximations = 0
1/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
-23682266742432/86209 - Approximations = 1
384201597749587/376965 - Approximations = 1
737142401693815/1022201 - Approximations = 1
-284674634303966/591759 - Approximations = 1
82166046046895/638798 - Approximations = 1
-41197517165269/241768 - Approximations = 1
-99842562869633/650417 - Approximations = 1
-538653187/851252925 - Approximations = 0
0/1 - Approximations = 0
1/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
134305155576051/716341 - Approximations = 1
-13203556738853/366200 - Approximations = 1
-24537672922118/82847 - Approximations = 1
16549480276482/195259 - Approximations = 1
318078124453980/649507 - Approximations = 1
-134672668171525/259953 - Approximations = 1
-177826968340988/360917 - Approximations = 1
-644567516/851252925 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
1/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
-3310742175483/10937 - Approximations = 1
38089339644151/44367 - Approximations = 2
-588517529215595/1467409 - Approximations = 1
26788526946040/434317 - Approximations = 1
-271720930109587/1703199 - Approximations = 1
50331968209596/229393 - Approximations = 1
31282761152975/503227 - Approximations = 1
-722347028/851252925 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
1/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
55223044767624/590287 - Approximations = 1
792481985903750/1639089 - Approximations = 2
21188682029327/57991 - Approximations = 1
121391497317435/1314869 - Approximations = 1
100882937820783/795179 - Approximations = 1
147943467335954/248541 - Approximations = 1
146343665474686/766673 - Approximations = 1
-22422524/56750195 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
1/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
-442828109356372/1138553 - Approximations = 1
148562416952300/233567 - Approximations = 2
64747470414887/90667 - Approximations = 1
-472192450868331/973469 - Approximations = 1
56787182225178/183551 - Approximations = 1
-61522571017139/174597 - Approximations = 1
-80358143448662/189973 - Approximations = 1
-511305061/851252925 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
1/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
-655534122402960/831419 - Approximations = 1
159430988842190/154787 - Approximations = 2
590543215316390/1006671 - Approximations = 1
-410456341802942/743569 - Approximations = 1
-308038049824643/1022112 - Approximations = 1
-26671328141969/242773 - Approximations = 1
-43038389523744/643837 - Approximations = 1
-129455192/170250585 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
0/1 - Approximations = 0
1/1 - Approximations = 0
Edited by czardas

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Then I guess I'm just plain not understanding how to use the fractions UDF.

Because I litterally replaced all normal math operations with your fractions version.

The version without fractions uses the exact same operations.... it should never try to divide by zero.... or I would experience the same failure when using the regular arithmetic operations...

It may try to divide by a decimal at some point, so could this be the problem? does your function fail to process 0.nnnnn ?

But as I understand using the fractions UDF to process my doubles, will still provide a more accurate end result after several iterations, so when I converted the final fractions back into doubles they would be more accurate than running several iterations of regular division of doubles over and over.

I have feeling that inaccuracies in my compression algorithm are to blame on this one function, because with each iteration the numbers become more and more inaccurate.

Edited by nullschritt

Share this post


Link to post
Share on other sites

Okay, I added in line to check to see if it was dividing by zero, and now it returns what I want. A 2D array containing all the fractions as sub-arrays.

But now I'm super confused as to my next step.

I need to allow my function to accept fractions or numbers as input, because this function has several iterations run on it, and the input of each is the output of the last, so the first time we input numbers and it returns an array of fractions, that much I've got down, but is it then possible to accept an array of fractions and preform the same operations on the fractions as if they were numbers, like 100/48 / 30/60 (dividing one fraction by another, or multiplying one fraction by another). Im sorry if I seem slow to pick up, I just don't fully understand your fractions UDF, and I don't recall how operations on fractions work from school.

Here's my code that works now:

#include "fractions.au3"
#include <array.au3>

$matricies = _loaddata(_datagen())

_inv_big($matricies[0])

Func _inv_big($m)
    Local $n = UBound($m, 1)
    Local $a[$n][2 * $n]
    Local $inv[$n][$n]
    Local $temprow[2 * $n]
    Local $pivelt, $tarelt, $pivrow, $tarrow, $k, $i, $j
    #Region - Filling matrix A
    For $i = 0 To $n - 1
        For $j = 0 To $n - 1
            $a[$i][$j] = $m[$i][$j]
        Next
    Next
    For $i = 0 To $n - 1
        $a[$i][$n + $i] = 1
    Next
    #EndRegion - Filling matrix A
    #Region - Inverting matrix $M

    Local $aExpression = 0
    Local $iExtended = 0

    For $pivrow = 0 To $n - 1
        $pivelt = $a[$pivrow][$pivrow]
        If ($pivelt == 0) Then
            $k = $pivrow + 1
            While ($pivelt == 0 And $k <= $n)
                $pivelt = $a[$k][$pivrow]
                $k = $k + 1
            WEnd
            If ($pivelt == 0) Then
                SetError(1)
                Return
            Else
                For $i = 0 To 2 * $n - 1
                    $temprow[$pivrow][$i] = $a[$pivrow][$i]
                    $k = $k - 1
                Next
                For $i = 0 To 2 * $n - 1
                    $a[$pivrow][$i] = $a[$k][$i]
                Next
                For $i = 0 To 2 * $n - 1
                    $a[$k][$i] = $temprow[$k][$i]
                Next
            EndIf
        EndIf
        For $i = 0 To 2 * $n - 1
           if Number($pivelt) <> 0 Then
            $a[$pivrow][$i] = _fraction(Number($a[$pivrow][$i]), Number($pivelt))
            EndIf
            If @error Then ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ERROR<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


                MsgBox(0, $pivelt, "ERROR" & @CRLF & (@error = 2) ? "You cannot divide by zero!" : "???")
                Exit
            EndIf

            ;array is accessable here
        Next
        #Region - replace all other rows by target
        For $tarrow = 0 To $n - 1
            If ($tarrow <> $pivrow) Then
                $tarelt = $a[$tarrow][$pivrow]
                For $i = 0 To 2 * $n - 1
                    $aExpression = _FractionMultiply($a[$pivrow][$i], _fraction(Number($tarelt)))
                    ;If @error Then MsgBox(0, "", "ERROR = " & @error)
                    If @extended Then $iExtended += 1 ; Approximation used
                    $a[$tarrow][$i] = _FractionSubtract(_fraction(Number($a[$tarrow][$i])), $aExpression)
                    If @extended Then $iExtended += 1 ; Approximation used
                    ;If @error Then MsgBox(0, "", "ERROR = " & @error)
                    ;_ArrayDisplay($a[$tarrow][$i])
                    ConsoleWrite(($a[$tarrow][$i])[0] & '/' & ($a[$tarrow][$i])[1] & " - Approximations = " & $iExtended & @CRLF)
                    $iExtended = 0
                Next
            EndIf
        Next
        #EndRegion - replace all other rows by target
    Next
    _ArrayDisplay($a[0][0])
    ;array is okay
    #Region - finally extract the inverse from columns N+1 to 2N
    For $i = 0 To $n - 1
        For $j = 0 To $n - 1
            $inv[$i][$j] = $a[$i][$n + $j]
        Next
    Next
    #EndRegion - finally extract the inverse from columns N+1 to 2N
    Return $inv
    #EndRegion - Inverting matrix $M
EndFunc   ;==>_inv_big

Func _datagen()
    Local $ret
    For $i = 1 To 112
        Local $data = ""
        For $x = 0 To 7
            For $y = 0 To 7
                $data &= Random(111111111, 99999999999, 1) & ","
            Next
            $data = StringTrimRight($data, 1) & "/"
        Next
        $ret &= StringTrimRight($data, 1) & "|"
    Next
    Return $ret
EndFunc   ;==>_datagen

Func _loaddata($data, $z = 112)
    Local $dataz[$z]
    $array = StringSplit($data, "|")
    If $array[0] < $z - 1 Then Return 0
    For $i = 0 To $z - 1
        $dataz[$i] = _stringtoarray($data, $i)
        If $dataz[$i] = 0 Then
            Return 0
        EndIf
    Next
    Return $dataz
EndFunc   ;==>_loaddata

Func _stringtoarray($data, $n = 0)
    $array = StringSplit($data, "|", 2)
    $next = StringSplit($array[$n], "/")
    $num2 = StringSplit($next[1], ",")
    Local $ar1[$next[0]][$num2[0]]
    For $i2 = 1 To $next[0]
        $next2 = StringSplit($next[$i2], ",", 2)
        For $i3 = 0 To UBound($next2) - 1
            If $i2 - 1 > $next[0] - 1 Or $i3 > $num2[0] - 1 Or $i3 > UBound($next2) Then
                Return 0
            EndIf
            $ar1[$i2 - 1][$i3] = $next2[$i3]
        Next
    Next
    Return $ar1
EndFunc   ;==>_stringtoarray

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

I haven't done extensive testing on the UDF. It seems you are quickly ending up with a lot of 15 digit numbers so approximations will occur. To add, multiply, subtract or divide; the divisors have to be multiplied together. If the result does not factorize easily then the numbers will remain large.

;

Fraction1 = Fraction2 / Fraction3

$a1 = _FractionDivide($a2, $a3) ; Returns a fraction

;

_Fraction(0.0001) works fine. If at some point I get the UDF to work with two Int64 values, it will always beat Double Precision for accuracy, hands down. :D

Never divide by zero!

Edited by czardas

Share this post


Link to post
Share on other sites

Also finding now that my algorithm isn't working properly, because the places where it wants to divide by zero are placeholders for re-arranging the data.

Just now realized that the output array now contains all the placeholders and the values. Gosh this is becoming a bit of a headache.

Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

LOL, I could have told you where the zeros were coming from. You need to go through every step carefully. I always make a scaled down version covering every step of a complex process. I write lots of comments to remind myself what I was thinking at the time, or why I changed something. I know the limitations of my UDF and I'm still unsure if it is adequate for this. As I said; the limitations may only be temporary, but fine tuning for greater accuracy will take time.

One more thing to be careful of (check for errors) is fraction approximation to zero ==> 0/1. The smallest value is:

1/999999999999999

Anything smaller than 1/1999999999999998 becomes zero.

Edited by czardas

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

Is there any way you could take a look at the function and maybe comment in what I need to change to make it function with strictly fractions? Converting my original input to fractions then the final output to decimal wouldn't be that difficult.

But I didn't code this function and I can't remember who did, and I'm having a really hard time grasping how to make it operate using functions in place of integers.

If you could find the time to show me what I'm doing wrong I would greatly appreciate it, I'm thinking it has something to do with the function not properly detecting the 1/0 and 0/1 when re-arranging the data as it's originally been coded to check ints not fraction.

This is what the function is attempting to achieve

inverse%20of%20a%20matrix%20example%201c

The first matrix(array) is the original, and the second is it's inverse, so this function is trying to take the original set of data and "inverse" it.

But this function has been designed to work with numbers, not fractions, but it's completley possible to use fractions inside of a matrix, I just have no real education with how fractions work, and so I'm over here scratching my head like an idiot trying to wonder how to get the function to properly re-arrange the data, it's properly generating the inverse fractions of the input fractions, but it's confused about how to resort the data because the placeholder digits are now fractions instead of ints :/

Edit: and I'm also guessing I would have to allow the fractions udf to divide by zero, since there's no actual dividing by zero going on, as those are just empty placeholders, to be disposed of.

Edited by nullschritt

Share this post


Link to post
Share on other sites

I guess I'll have to give up for now and move on to other more pressing features of my project. I already have a feature that automatically corrects corrupted data by reprocessing it, and this is still several hundred times faster than using bignum to get an accurate result.

You functions UDF seemed a lot more lightweight, and to be honest, I'm not 100% sure it would completely fix the corruption, I was simply hoping that it might improve the percentage of the time that the output came out correct by reducing the inaccuracies in autoit-its handling of doubles.

Share this post


Link to post
Share on other sites

When you get the time could you write a version of the _fraction() function that accepts values to be divided by zero(since your function isn't actually preforming the division)? At least then I would be able to store all the appropriate values in the array, then I would just have to figure out what part of the function needs those values.

Share this post


Link to post
Share on other sites

I wouldn't give up on it altogether. Sometimes taking a step back gives you more perspective. In all honesty I'm reasonably happy with the UDF, but not quite as happy as I originally wanted to be.

Regarding division by zero. You can do it as much as you like using _Fraction() so long as you do not try and access the non-existent array afterwards. That's where the interpreter throws an error. The same applies with numbers: after division by zero infinity is returned (or rather a representation of infinity) and AutoIt does not throw an error. Of course it's wrong to divide by zero in both cases and I have no intentions of overriding the current behaviour. All the checks you need are already provided.

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

Here a fast hack for a 2x2 matrix:

;a fast hack version by UEZ
#include <Array.au3>
#include <EditConstants.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>

Global $hGUI = GUICreate("2x2 Matrix Invers", 500, 306, -1, -1)
Global $iLabel = GUICtrlCreateLabel("2x2 Matrix Invers", 40, 20, 400, 40, $SS_CENTER)
GUICtrlSetFont(-1, 20, 400, 0, "Arial", 5)
Global $hLabel2 = GUICtrlCreateLabel("Matrix A", 80, 90, 100, 28, $SS_CENTER)
GUICtrlSetFont(-1, 20, 400, 0, "Times New Roman", 5)
Global $iInput_A = GUICtrlCreateInput("4.25", 80, 130, 40, 30, $SS_CENTER)
Global $iInput_B = GUICtrlCreateInput("7/2", 130, 130, 40, 30, $SS_CENTER)
Global $iInput_C = GUICtrlCreateInput("3", 80, 165, 40, 30, $SS_CENTER)
Global $iInput_D = GUICtrlCreateInput("2", 130, 165, 40, 30, $SS_CENTER)
Global $hLabel3 = GUICtrlCreateLabel("Matrix A'", 280, 90, 100, 28, $SS_CENTER)
GUICtrlSetFont(-1, 20, 400, 0, "Times New Roman", 5)
Global $iInput_Ai = GUICtrlCreateInput("", 280, 130, 100, 30, BitOR($ES_READONLY, $SS_CENTER))
Global $iInput_Bi = GUICtrlCreateInput("", 390, 130, 100, 30, BitOR($ES_READONLY, $SS_CENTER))
Global $iInput_Ci = GUICtrlCreateInput("", 280, 165, 100, 30, BitOR($ES_READONLY, $SS_CENTER))
Global $iInput_Di = GUICtrlCreateInput("", 390, 165, 100, 30, BitOR($ES_READONLY, $SS_CENTER))
Global $iButton = GUICtrlCreateButton("Calculate", 280, 230, 90, 60)
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            GUIDelete()
            Exit
        Case $iButton
            Calc_InversMatrix()
    EndSwitch
WEnd

Func Calc_InversMatrix()
    Local $aMatrix[2][2] = [[Execute(GUICtrlRead($iInput_A)), Execute(GUICtrlRead($iInput_B))], [Execute(GUICtrlRead($iInput_C)), Execute(GUICtrlRead($iInput_D))]]
    If Not $aMatrix[1][0] And Not $aMatrix[1][1] Then Return SetError(1, 0, 0) ; -> determinant is zero, therefore inverse matrix doesn't exist
    Local $fDetA = 1 / ($aMatrix[0][0] * $aMatrix[1][1] - $aMatrix[1][0] * $aMatrix[0][1]), $f
    $f = Number($fDetA * $aMatrix[1][1])
    GUICtrlSetData($iInput_Ai, Float2Frac($f))
    GUICtrlSetTip($iInput_Ai, $f)
    $f = Number($fDetA * -$aMatrix[0][1])
    GUICtrlSetData($iInput_Bi, Float2Frac($f))
    GUICtrlSetTip($iInput_Bi, $f)
    $f = Number($fDetA * -$aMatrix[1][0])
    GUICtrlSetData($iInput_Ci, Float2Frac($f))
    GUICtrlSetTip($iInput_Ci, $f)
    $f = Number($fDetA * $aMatrix[0][0])
    GUICtrlSetData($iInput_Di, Float2Frac($f))
    GUICtrlSetTip($iInput_Di, $f)
EndFunc   ;==>Calc_InversMatrix

Func Float2Frac($fFloat, $iAccuracy = 5) ;coded by UEZ
    If Not IsNumber($fFloat) Then Return SetError(1, 0, 0)
    Local $iDec = StringLen(StringRegExpReplace($fFloat, "\d+\.(\d*)", "\1"))
    $iAccuracy = $iAccuracy > 10 ? 10 : $iAccuracy
    $iDec = $iDec > $iAccuracy ? $iAccuracy : $iDec
    Local $iZaehler = Round($fFloat * 10 ^ $iDec, 0)
    Local $iNenner = 10 ^ $iDec
    Local $iGGT = Number(ggT(Int($iZaehler), Int($iNenner)))
    ConsoleWrite("Float: " & $fFloat & @CRLF)
    ConsoleWrite("Dec: " & $iDec & @CRLF)
    ConsoleWrite("Zaehler: " & $iZaehler & @CRLF)
    ConsoleWrite("Nenner: " & $iNenner & @CRLF)
    ConsoleWrite("$iGGT: " & $iGGT & @CRLF)
    ConsoleWrite($fFloat & " -> " & $iZaehler / $iGGT & " / " & $iNenner / $iGGT & @CRLF & @CRLF)
    If $iGGT < 0 Then
        $iZaehler /= $iGGT * -1
        $iNenner /= $iGGT * -1
    Else
        $iZaehler /= $iGGT
        $iNenner /= $iGGT
    EndIf
    Return $iZaehler & " / " & $iNenner
EndFunc   ;==>Float2Frac

Func ggT($a, $b) ;coded by UEZ 2012
    If Not IsInt($a) Then Return SetError(1, 0, 0)
    If Not IsInt($b) Then Return SetError(2, 0, 0)
    If $a = $b Then Return Abs($a)
    If Not $a And $b Then Return Abs($a)
    If $a And Not $b Then Return Abs($b)
    If ($a And $b = 1) Or ($a = 1 And $b) Then Return 1
    Local $iMod
    Do
        $iMod = Mod($a, $b)
        If Not $iMod Then ExitLoop
        $a = $b
        $b = $iMod
    Until False
    Return $b
EndFunc   ;==>ggT
Edited by UEZ
1 person likes this

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now