nullschritt Posted March 9, 2015 Share Posted March 9, 2015 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>>) expandcollapse popup#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 Link to comment Share on other sites More sharing options...
mikell Posted March 9, 2015 Share Posted March 9, 2015 (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 March 9, 2015 by mikell Link to comment Share on other sites More sharing options...
czardas Posted March 9, 2015 Share Posted March 9, 2015 (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 March 9, 2015 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
nullschritt Posted March 9, 2015 Author Share Posted March 9, 2015 (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 March 9, 2015 by nullschritt Link to comment Share on other sites More sharing options...
nullschritt Posted March 9, 2015 Author Share Posted March 9, 2015 (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 March 9, 2015 by nullschritt Link to comment Share on other sites More sharing options...
czardas Posted March 9, 2015 Share Posted March 9, 2015 (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 March 9, 2015 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
nullschritt Posted March 10, 2015 Author Share Posted March 10, 2015 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. Link to comment Share on other sites More sharing options...
markyrocks Posted March 10, 2015 Share Posted March 10, 2015 (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 March 10, 2015 by markyrocks Spoiler "I Believe array math to be potentially fatal, I may be dying from array math poisoning" Link to comment Share on other sites More sharing options...
czardas Posted March 10, 2015 Share Posted March 10, 2015 (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. ; expandcollapse popup#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: expandcollapse popup0/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 March 10, 2015 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
nullschritt Posted March 10, 2015 Author Share Posted March 10, 2015 (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 March 10, 2015 by nullschritt Link to comment Share on other sites More sharing options...
nullschritt Posted March 10, 2015 Author Share Posted March 10, 2015 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: expandcollapse popup#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 Link to comment Share on other sites More sharing options...
czardas Posted March 10, 2015 Share Posted March 10, 2015 (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. Never divide by zero! Edited March 10, 2015 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
nullschritt Posted March 10, 2015 Author Share Posted March 10, 2015 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. Link to comment Share on other sites More sharing options...
czardas Posted March 10, 2015 Share Posted March 10, 2015 (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 March 10, 2015 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
nullschritt Posted March 10, 2015 Author Share Posted March 10, 2015 (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 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 March 10, 2015 by nullschritt Link to comment Share on other sites More sharing options...
czardas Posted March 10, 2015 Share Posted March 10, 2015 Well it's the first time I've looked at matrix inversion. To be honest I'd need time to study this which I don't have. If you don't understand the code you posted, that makes two of us I'm afraid. I took a quick look here: http://mathworld.wolfram.com/MatrixInverse.html operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
nullschritt Posted March 10, 2015 Author Share Posted March 10, 2015 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. Link to comment Share on other sites More sharing options...
nullschritt Posted March 10, 2015 Author Share Posted March 10, 2015 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. Link to comment Share on other sites More sharing options...
czardas Posted March 10, 2015 Share Posted March 10, 2015 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. operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
UEZ Posted March 10, 2015 Share Posted March 10, 2015 (edited) Here a fast hack for a 2x2 matrix:expandcollapse popup;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 March 16, 2015 by UEZ czardas 1 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now