I wanted to multiply 2 matrices in codesys. I have implemented the code in the structured text language. However I am not able to generate the results correctly. Below is the logic which i am trying to implement.
Initialisation in codesys:
PROGRAM POU
VAR
a: ARRAY [1..5,1..2] OF INT:= [1,2,3,4,5,6,7,8,9,1];
b: ARRAY [1..2,1..5] OF INT := [1,2,3,4,5,6,7,8,9,1];
r1: INT:= 5; // no. of rows in a;
c1: INT:=2; // no. of columns in a;
r2: INT:= 2; //no. Of rows in b;
c2: INT:= 5; //no. of columns in b;
i: INT;
j: INT ;
k: INT;
z: INT:=2;
result: ARRAY [1..5,1..5] OF INT:= 0;
END_VAR
Program logic:
FOR i:=1 TO r1 DO
FOR j:=1 TO c2 DO
FOR k:=1 TO z DO
result[i,j]:= result[i,j]+(a[i,k]*b[k,j]);
END_FOR
END_FOR
END_FOR
What may be the reason for not getting the desired output?
The only obvious problem I see is, if you want to initialize an array with a specific value, don't do result: ARRAY [1..5, 1..5] OF INT := 0 as you would should get an error C0032: Cannot convert type 'BIT' to type 'ARRAY [1..5, 1..5] OF INT', instead do this: result: ARRAY [1..5, 1..5] OF INT := [ 25(0) ], although in codesys arrays Elements to which no initialization value is assigned explicitly are initialized internally with the default value of the basic data type, which in case of an INT is 0.
Also, to avoid errors, instad of hardcoding the boundaries I'd recomment to instad use the built in LOWER_BOUND an UPPER_BOUND functions.
Here's an example generic function for Matrix multiplication based on the code in your question:
METHOD IntMatrixProduct : BOOL
VAR_IN_OUT
A: ARRAY [*, *] OF INT;
B: ARRAY [*, *] OF INT;
C: ARRAY [*, *] OF INT;
END_VAR
VAR_INPUT
zero_C: BOOL := TRUE;
END_VAR
VAR
al1: DINT := LOWER_BOUND(A, 1);
au1: DINT := UPPER_BOUND(A, 1);
al2: DINT := LOWER_BOUND(A, 2);
au2: DINT := UPPER_BOUND(A, 2);
bl1: DINT := LOWER_BOUND(B, 1);
bu1: DINT := UPPER_BOUND(B, 1);
bl2: DINT := LOWER_BOUND(B, 2);
bu2: DINT := UPPER_BOUND(B, 2);
cl1: DINT := LOWER_BOUND(C, 1);
cu1: DINT := UPPER_BOUND(C, 1);
cl2: DINT := LOWER_BOUND(C, 2);
cu2: DINT := UPPER_BOUND(C, 2);
height: DINT := au1 - al1;
width: DINT := bu2 - bl2;
common: DINT := au2 - al2;
i, j, k: DINT;
END_VAR
IF (common <> bu1 - bl1 // Width of A != Height of B
OR_ELSE cu1 - cl1 <> height // Height of C != Height of A
OR_ELSE cu2 - cl2 <> width) THEN // Width of C != Width of B
IntMatrixProduct := FALSE; // Error!
RETURN;
END_IF
// Zero C
IF (zero_C) THEN
FOR i := 0 TO height DO
FOR j := 0 TO width DO
result[cl1 + i, cl2 + j] := 0;
END_FOR
END_FOR
END_IF
// Calcutale A*B
FOR i := 0 TO height DO
FOR j := 0 TO width DO
FOR k := 0 TO common DO
result[cl1 + i, cl2 + j] := result[cl1 + i, cl2 + j] + (a[al1 + i, al2 + k] * b[bl1 + k, bl2 + j]);
END_FOR
END_FOR
END_FOR
IntMatrixProduct := TRUE; // Success
You can also try importing the code using PLCOpen from here.
PS. Here's the result I get after running the above function:
Related
I need use loop from title,but I get incorrect value of result, under my code,please for suggestion, when i use a for everything is ok
const
licz_l = 5;
var
x, suma, min, max: longint;
tab: array [1..5] of longint;
begin
randomize();
suma := 0;
x := 0;
repeat
tab[x] := random(100);
suma := suma + tab[x];
write({'wylosowane liczby : ',}tab[x],';');
min := tab[1];
max := tab[1];
if (tab[x] < min) then
min := tab[x];
// max:=tab[1];
if (max < tab[x]) then
max := tab[x];
x := x + 1;
until x = licz_l;
writeln('');
writeln('srednia : ', suma / licz_l : 4 : 4);
writeln('min : ', min, #9, 'max : ', max);
end.
New code with second loop [for], but like I write, is a posibility to use only one loop[repeat until] to getvthe same effect?
const
licz_l = 5;
var
x, suma, min, max: longint;
tab: array [0..4] of longint;
begin
randomize();
suma := 0;
x := 0;
repeat
tab[x] := random(100);
suma := suma + tab[x];
write({'wylosowane liczby : ',}tab[x],';');
x := x + 1;
until x = licz_l;
min := tab[0];
max := tab[0];
for x := 0 to licz_l-1 do
begin
if (tab[x] < min) then
min := tab[x];
if (max < tab[x]) then
max := tab[x];
end;
writeln('');
writeln('srednia : ',suma/licz_l:4:4);
writeln('min : ',min,#9,'max : ',max);
end.
There are two possible ways to correct your first code (with a single loop).
Remove the lines within the loop: min := tab[1]; and max := tab[1];
Initialize min and max before the loop, with values that are,
on one hand > maximum value that random(100) may return, and
on other hand < minimum value that random(100) may return.
or
Assign min and max unconditionally with the first value, but only the first time your loop runs (if x = 0).
const
licz_l=5;
var
x,suma,min,max: longint;
tab: array [0..4] of longint;
begin
randomize();
suma:=0;
x:=0;
repeat
tab[x]:=random(100);
suma:=suma+tab[x];
write((*'wylosowane liczby : ',*)tab[x],';');
x:=x+1;
until x=licz_l;
min:=tab[0];
max:=tab[0];
for x:=0 to licz_l-1 do
begin
if (tab[x]<min) then
min:=tab[x];
if (max<tab[x]) then
max:=tab[x];
end;
writeln('');
writeln('srednia : ',suma/licz_l:4:4);
writeln('min : ',min,#9,'max : ',max);
end.
Or
const
licz_l = 5;
var
x, suma, min, max: longint;
tab: array [0..4] of longint;
begin
randomize();
suma := 0;
x := 0;
min := 99;
max := 0;
repeat
tab[x] := random(100);
suma := suma + tab[x];
write((*'wylosowane liczby : ',*)tab[x],';');
//min := tab[0];
//max := tab[0];
if (tab[x] < min) then
min := tab[x];
if (max < tab[x]) then
max := tab[x];
x := x + 1;
until x = licz_l;
writeln('');
writeln('srednia : ', suma / licz_l : 4 : 4);
writeln('min : ', min, #9, 'max : ', max);
end.
I need to sort arrays by integer field, with 1-n sorted at the beginning and zeros last:
0,0,3,1,2 -> 1,2,3,0,0
I don't know how to sort it in one go, so I tried in 2 sorts, but it doesn't produce correct results:
It does put zeros at the end, but it messes up 1-n ordered items:
0,0,3,1,2 -> (first sort) 0,0,1,2,3 -> (second sort) 2,3,1,0,0
procedure TForm2.Button1Click(Sender: TObject);
var
Arr: TArray<integer>;
begin
SetLength(Arr, 5);
Arr[0] := 0;
Arr[1] := 0;
Arr[2] := 3;
Arr[3] := 1;
Arr[4] := 2;
// First sort: Sort 1-n
TArray.Sort<integer>(Arr, TComparer<integer>.Construct(function(const Left, Right: integer): Integer
begin
if Left < Right then
Result := -1
else if Left > Right then
Result := 1
else
Result := 0;
end
));
// Second sort: Put zeros at the end
TArray.Sort<integer>(Arr, TComparer<integer>.Construct(function(const Left, Right: integer): Integer
begin
if (Left = 0) and (right>0) then
Result := 1
else
Result := 0;
end
));
end;
Is there a way to do this kind of sort in one, single Sort operation?
Try this, the point being to deal with the special 0 cases first in the if-then-else ladder, before the ordinary cases.
TArray.Sort<integer>(Arr, TComparer<integer>.Construct(function(const Left, Right: integer): Integer
begin
if (Left = 0) and (Right = 0) then
Result := 0
else if (Left = 0) then
Result := 1
else if (Right = 0) then
Result := -1
else if (Left < Right) then
Result := -1
else if (Left > Right) then
Result := 1
else
Result := 0;
end
));
A brief testing shows it works OK.
Just fix your compare function so that it will treat 0 as being larger than anything.
Untested:
TArray.Sort<integer>(Arr, TComparer<integer>.Construct(function(const Left, Right: integer): Integer
begin
if Left = Right then
Result := 0
else if ((Left <> 0) and (Left < Right)) or (Right = 0) then
Result := -1
else
Result := 1;
end
));
Objective: I have been solving question 6 from the book 'Cracking the Coding interview' by using Go.
NOTE I DO NOT WAN'T HELP OR SOLUTIONS TO THIS QUESTION
Given an image represented by an NxN matrix, where each pixel in the image is 4
bytes, write a method to rotate the image by 90 degrees. Can you do this in place?
Problem: I made an array of arrays to represent the matrix and I created a swap function to swap the elements clockwise in the matrix. For some reason I get this really weird error when trying to compile:
./Q6.go:29: invalid operation: b[N - col - 1] (index of type *int)
./Q6.go:30: invalid operation: b[N - row - 1] (index of type *int)
Where am I getting type *int as an index? In the Go documenation, len(v) returns type int and everything else is in the value of 'N - col - 1' is type int so how am I getting type *int index?
Code:
package main
import "fmt"
func main() {
b := [][]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}} // 4 by 4 array going from 1 to 16
N := len(b)
for row := 0; row < N / 2; row++ {
for col := row; col < N - row - 1; col++ {
a := &b[row][col]
b := &b[col][N - row - 1]
c := &b[N - col - 1][col] // <-- Error here
d := &b[N - row - 1][N - col - 1] // <-- Error here
fourSwap(a, b, c, d)
}
}
for r := range b {
for c:= range b[0] {
fmt.Print(b[r][c])
}
fmt.Print("\n")
}
}
// [a][-][-][b] [c][-][-][a]
// [-][-][-][-] --> [-][-][-][-]
// [-][-][-][-] --> [-][-][-][-]
// [c][-][-][d] [d][-][-][b]
func fourSwap(a, b, c, d *int) {
temp := *b
*b = *a
*a = *c
*c = *d
*d = temp
}
You declare b inside the loop, and that shadows your slice.
for row := 0; row < N / 2; row++ {
for col := row; col < N - row - 1; col++ {
a := &b[row][col]
b := &b[col][N - row - 1] <<<< b is now an *int
c := &b[N - col - 1][col] // <-- Error here
d := &b[N - row - 1][N - col - 1] // <-- Error here
fourSwap(a, b, c, d)
}
}
You are creating a new local variable b which is a pointer on the line before you get the error:
b := &b[col][N - row - 1]
I have three points that form a triangle (obviously). But I don't want to draw this triangle but a smaller one inside.
How do I do that with Cairo in C?
I think you need to calculate the vertices of new triangle whose sides are equidistant from the sides of the old triangle.
Find unit vectors for adjacent triangle sides BD = BA / |BA|, BE = BC / |BC| ... (|BA| is length of vector BA)
Find unit bisector BF = (BD + BE) / |BD + BE|
Find final position of F point (bisector of needed length) BF = BF * NeededDistance / (BF x BE) ...(denominator is cross product, it is equal to Sin(ABC/2)
Do the same for G and H vertices.
Delphi code and result:
var
P, V: array[0..2] of TPoint;
i, inext, iprev: Integer;
nx, ny, px, py, mx, my, coeff: Double;
distance: Integer;
procedure NormalizeVector(var dx, dy: Double);
var
revlen: Double;
begin
revlen := 1.0 / Hypot(dx, dy);
dx := dx * revlen;
dy := dy * revlen;
end;
begin
Canvas.Brush.Color := Color;
Canvas.FillRect(ClientRect); //clean the blackboard
Randomize;
//big triangle vertices
for i := 0 to 2 do
P[i] := Point(Random(500), Random(500));
//draw big triangle
Canvas.Brush.Style := bsClear;
Canvas.Polygon(P);
for i := 0 to 2 do begin
inext := (i + 1) mod 3; // next vertice index
iprev := (i - 1 + 3) mod 3; // previous vertice index
nx := P[inext].X - P[i].X; //vector to the next vertice
ny := P[inext].Y - P[i].Y;
px := P[iprev].X - P[i].X; //vector to the previous vertice
py := P[iprev].Y - P[i].Y;
NormalizeVector(nx, ny); //make unit vectors
NormalizeVector(px, py);
mx := nx + px;
my := ny + py;
NormalizeVector(mx, my); //unit bisector
distance := 20;
coeff := distance / (mx * py - my * px);
mx := mx * coeff;
my := my * coeff;
//inner triangle vertice
V[i] := Point(P[i].X + Round(mx), P[i].Y + Round(my));
end;
//draw inner triangle
Canvas.Polygon(V);
Pascal apparently has string concatenation, but does it have general concatenation for any type of array?
It does not but you can make your own function i coded this in 5 minutes...i am shure there is a better method but i don't have any idea right now.
type
TBArray = array of byte;
function ConcArray(arr1,arr2:TBArray):TBArray;
begin
SetLength(Result,Length(arr1) + Length(arr2));
ZeroMemory(#Result[0],Length(arr1) + Length(arr2));
CopyMemory(#Result[0],#arr1[0],Length(arr1));
CopyMemory(#Result[Length(arr1)],#arr2[0],Length(arr2));
end;
How about this? If you need to concatenate in many places, the + operator looks pretty nice IMHO.
program ConCatTest;
type
SomeRec = record
s: AnsiString;
i: Longint;
end;
SomeArr = array of SomeRec;
operator + (a, b: SomeArr) c: SomeArr;
var
i: Longint;
begin
SetLength(c, Length(a) + Length(b));
for i := 0 to High(a) do
c[i] := a[i];
for i := 0 to High(b) do
c[i + Length(a)] := b[i];
end;
var
a1, a2, a3: SomeArr;
i: Longint;
begin
SetLength(a1, 3);
SetLength(a2, 2);
a1[0].s := 'a';
a1[0].i := 0;
a1[1].s := 'a';
a1[1].i := 1;
a1[2].s := 'a';
a1[2].i := 2;
a2[0].s := 'b';
a2[0].i := 0;
a2[1].s := 'b';
a2[1].i := 1;
a3 := a1 + a2;
for i := 0 to High(a3) do
WriteLn(a3[i].s, a3[i].i);
ReadLn;
end.