Bash - a multiplying two-dimensional matrix

Suppose I have a two-dimensional matrix nxn, and we already know n = 4 and values ​​1 to 16, similar this

I have to multiply parts like:

Array1 * Array2 = result

Array3 * result = result1

Array4 * result1 = result2

ShowMatrix() { echo "MyMatrix is:" for((i=0;i<$n;i++))do for((j=0;j<$n;j++))do printf ' '${myArray[i*n+j]} done printf '\n'; done } 

I tried to divide it into 4 parts, as in the diagram, and assign each part to Array1, Array2, Array3 and Array4

 cut1() { for((i=0;i<$n/2;i++))do for((j=0;j<$n/2;j++))do Array1[i*n+j]=${myArray[i*n+j]} done done } cut2() { for((i=0;i<$n/2;i++))do for((j=$n/2;j<$n;j++))do Array2[i*n+j]=${myArray[i*n+j]} done done } cut3() { for((i=$n/2;i<$n;i++))do for((j=0;j<$n/2;j++))do Array3[i*n+j]=${myArray[i*n+j]} done done } cut4() { for((i=$n/2;i<$n;i++))do for((j=$n/2;j<$n;j++))do Array4[i*n+j]=${myArray[i*n+j]} done done } 

After that I tried to propagate them, as in the diagram:

Array1 * Array2 = result

Array3 * result = result1

Array4 * result1 = result2

 multiply() { for((i=0;i<$n;i++))do for((j=0;j<$n;j++))do result[i*n+j]=0 for((k=0;k<$n;k++))do let "result[i*n+j]=${result[i*n+j]}+${Array1[i*n+k]}*${Array2[k*n+j]}" done done done } multiply1() { for((i=0;i<$n;i++))do for((j=0;j<$n;j++))do result1[i*n+j]=0 for((k=0;k<$n;k++))do let "result1[i*n+j]=${result1[i*n+j]}+${result[i*n+k]}*${Array3[k*n+j]}" done done done } multiply2() { for((i=0;i<$n;i++))do for((j=0;j<$n;j++))do result2[i*n+j]=0 for((k=0;k<$n;k++))do let "result2[i*n+j]=${result2[i*n+j]}+${result1[i*n+k]}*${Array4[k*n+j]}" done done done } 

And the results after calling the functions:

 cut1 cut2 cut3 cut4 multiply multiply1 multiply2 echo "result is:" for((i=0;i<$n;i++))do for((j=0;j<$n;j++))do printf ' '${result[i*n+j]} done printf '\n'; done echo "result1 is:" for((i=0;i<$n;i++))do for((j=0;j<$n;j++))do printf ' '${result1[i*n+j]} done printf '\n'; done echo "result2 is:" for((i=0;i<$n;i++))do for((j=0;j<$n;j++))do printf ' '${result2[i*n+j]} done printf '\n'; done 
+6
source share
1 answer

The main conceptual problem with the written code is that you divide a large array into smaller pieces, but then do not adjust the reduced size of these fragments.

In particular, one specific error in the cut functions. When saving to Array1..Array3, you use the indexes of the larger array, not the smaller array. The POSIX shell and bash happily expand the missing entries and fill them with zeros. Therefore, bash will not help you find your error here.

Similarly, multiplication functions should only try to multiply by the boundaries of reduced size arrays. Saving a 2D array as a linear array, getting the side of the array is a little more complicated: either you pass the dimensions, as I do below, or you can select the size from the array (provided that it was initialized correctly) and accept the square root.

You mention what you perceive as random behavior. I suspect that what is happening here is that a dynamic variable looking from your environment or from a past execution represents a value for values ​​in various subroutines. To protect against this, I would declare all local variables inside the function. Of course, there are arrays that are not local, but again, inside the program, you must also state this.

That is why I think that others have suggested that you use a more appropriate language to do something like this. And I agree with these estimates.

But if you need to use the POSIX shell, you probably should know and use it better. You can syntax check your code with bash -n . If the code is POSIX compatible, then I highly recommend it here, then ksh -n will provide you with more thorough and detailed criticism of the program.

To help you find errors in this program, kind, I suggest a bash debugger . And for code testing, I would suggest the Kate Ward Unit Test shunit program .

I rewrote the error correction code. As far as I can tell, this follows what you say and whether you want to have code. However, you never described what you are trying to do, or give the expected answer to the specific data that you have, so I have no way to verify things myself.

The only thing I would recommend doing but not doing below is DRY (Do not Repeat Yourself). 4 section functions can be collapsed into a single procedure if you pass the start and end points and the name of the array in which you want to save the result. I think you have to use eval here.

Similarly, three multiplication functions can be grouped into one, passing the names of the arrays on which the processing is performed.

I removed the duplicate code showing the array by raising your ShowMatrix routine.

 typeset -ir n=4 typeset -a Array=() typeset -a Array1=() typeset -a Array2=() typeset -a Array3=() typeset -a Array4=() typeset -a Result=() typeset -a Result1=() typeset -a Result2=() ShowMatrix() { typeset arr=$1 typeset n=$2 typeset -ii echo "Matrix $arr is:" for ((i=0;i<n;i++)) ; do typeset -ij typeset -i val for ((j=0;j<n;j++)) ; do ((val=${arr}[i*n+j])) printf '%5d ' $val done printf '\n'; done } cut1() { typeset -ii typeset -ik=0 for((i=0;i<n/2;i++)) ; do typeset -ij for((j=0;j<n/2;j++)); do ((Array1[k++] = Array[i*n+j])) done done } cut2() { typeset -ii typeset -ik=0 for((i=0;i<n/2;i++)) ; do typeset -ij for((j=n/2;j<n;j++)) ; do ((Array2[k++] = Array[i*n+j])) done done } cut3() { typeset -ii typeset -ik=0 for((i=n/2;i<n;i++)) ; do for((j=0;j<n/2;j++)) ; do ((Array3[k++] = Array[i*n+j])) done done } cut4() { typeset -ii typeset -ik=0 for((i=n/2;i<n;i++)) ; do for((j=n/2;j<n;j++)); do ((Array4[k++] = Array[i*n+j])) done done } multiply() { typeset -ii typeset -in=$1 ShowMatrix Array1 $n ShowMatrix Array2 $n for((i=0;i<n;i++)); do typeset -ij for((j=0; j < n; j++)); do typeset -il ((l=i*n+j)) ((Result[l]=0)) typeset -ik for((k=0; k<n; k++)) ; do ((Result[l] += Array1[i*n+k]*Array2[k*n+j])) done done done } multiply1() { typeset -in=$1 ShowMatrix Result $n ShowMatrix Array3 $n typeset -ii for((i=0; i < n; i++)) ; do typeset -ij for((j=0; j < n; j++)); do typeset -il ((l=i*n+j)) ((Result1[i*n+j]=0)) typeset -ik for ((k=0;k<n;k++)); do ((Result1[l] += Result[i*n+k]*Array3[k*n+j])) done done done } multiply2() { typeset -ii typeset -in=$1 ShowMatrix Result1 $n ShowMatrix Array4 $n for ((i=0; i<n; i++)) ; do typeset -ij for ((j=0; j < n; j++)) ; do typeset -il ((l=i*n+j)) ((Result2[i*n+j]=0)) typeset -ik for((k=0;k<n;k++)); do ((Result2[l] += Result1[i*n+k]*Array4[k*n+j])) done done done } typeset -ii for((i=0; i<n*n; i++)) ; do ((Array[i]=i+1)) done cut1 cut2 cut3 cut4 typeset -i n2 ((n2 = n / 2)) multiply $n2 multiply1 $n2 multiply2 $n2 ShowMatrix Result2 $n2 
+1
source

Source: https://habr.com/ru/post/980785/


All Articles