Recent

Author Topic: Add arrays into one ?  (Read 10827 times)

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Add arrays into one ?
« on: November 05, 2021, 03:13:13 pm »
Hello.

What is the fastest-best way to add arrays of float into one ?

I use the "classical" way, something like this:

Code: Pascal  [Select][+][-]
  1. ...
  2.  
  3. var
  4. arr0, arr1, arr2, arr3 : array of cfloat;
  5.  
  6. ...
  7.  
  8. procedure AddArrays();
  9. var
  10.   i : integer;
  11.   begin
  12.   // all arrays have the same size
  13.     for i := 0 to length(arr0) -1 do
  14.     arr0[i] := arr1[i] + arr2[i] + arr3[i];
  15.   end;
  16.  

Thanks.

Fre;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Add arrays into one ?
« Reply #1 on: November 05, 2021, 04:15:22 pm »
This came up this week.  There is compiler support for it in two ways: See: https://forum.lazarus.freepascal.org/index.php/topic,57009.0.html
and the link to Rosetta code.
Both the + operator and Concat() are fast and safe.
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$modeswitch arrayoperators+}
  3. var
  4.   arr0, arr1, arr2, arr3 : array of single;
  5. begin
  6.   arr0 := concat(arr1,arr2,arr3);
  7.   // or
  8.   arr0 := arr1+arr2+arr3;
  9. end.
The concat() may be very slightly faster.
In Delphi mode the array + operator is on by default. Concat() can be used in almost all modes.
Also note FPC can optimize your code using simd instructions on Intel and Arm, so experiment with the compiler settings.  Concat() and + may need FPC to rebuild the compiler and rtl with optimum settings for maximum speed. For audio - I believe your interest -, this is certainly worth the trouble. FPC is build rather conservative as standard.
You could try and build FPC and RTL with -CfAVX2 and with -dFASTMATH for Intel. This will still cover most Intel/AMD machines in the wild. For arm, something similar can be done.
« Last Edit: November 05, 2021, 04:55:41 pm by Thaddy »
Specialize a type, not a var.

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Add arrays into one ?
« Reply #2 on: November 05, 2021, 05:01:43 pm »
I think the addition is element for element into an array of the same dimension as the other three.
In which case I think the OP's method looks OK.
But I could be wrong of course.
« Last Edit: November 05, 2021, 05:05:35 pm by BobDog »

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: Add arrays into one ?
« Reply #3 on: November 05, 2021, 05:38:23 pm »
This came up this week.  There is compiler support for it in two ways: See: https://forum.lazarus.freepascal.org/index.php/topic,57009.0.html
and the link to Rosetta code.
Both the + operator and Concat() are fast and safe.
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$modeswitch arrayoperators+}
  3. var
  4.   arr0, arr1, arr2, arr3 : array of single;
  5. begin
  6.   arr0 := concat(arr1,arr2,arr3);
  7.   // or
  8.   arr0 := arr1+arr2+arr3;
  9. end.
The concat() may be very slightly faster.
In Delphi mode the array + operator is on by default. Concat() can be used in almost all modes.
Also note FPC can optimize your code using simd instructions on Intel and Arm, so experiment with the compiler settings.  Concat() and + may need FPC to rebuild the compiler and rtl with optimum settings for maximum speed. For audio - I believe your interest -, this is certainly worth the trouble. FPC is build rather conservative as standard.
You could try and build FPC and RTL with -CfAVX2 and with -dFASTMATH for Intel. This will still cover most Intel/AMD machines in the wild. For arm, something similar can be done.

Thanks Thaddy, I will deeply study your post, write you later.

Quote
For audio - I believe your interest -,
Indeed!  ;)

By the way, about apply a multiplication to a array, something like this, is there also a other solution?

Code: Pascal  [Select][+][-]
  1. var
  2.  arr0: array of cfloat;
  3.  fl : cfloat = 0.3456 ; // ok Thaddy!
  4.  
  5. ...
  6.  
  7. procedure MultipliArray();
  8. var
  9.   i : integer;
  10.    begin
  11.       for i := 0 to length(arr0) -1 do
  12.     arr0[i] := arr0[i] * fl;
  13.   end;

@BobDog : thanks for your post.  Yes it is ok but maybe, like explained Thaddy, optimization can be done.

Fre;D
« Last Edit: November 05, 2021, 07:18:19 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Add arrays into one ?
« Reply #4 on: November 05, 2021, 05:46:09 pm »
I think the addition is element for element into an array of the same dimension as the other three.
In which case I think the OP's method looks OK.
But I could be wrong of course.
No you are not wrong. But the compiler can use simd instructions for simple math (vectors here)  and that can lead to a considerable speed increase and that is what Fred wants.
This is not about the algorithm perse, but about squeezing the most speed - within reason - out of the compiler. In effect my suggestion is that Fred ends up with a compiler and rtl that is specifically suited to audio.. :D (because + and concat() will be optimized)
Then you don't need assembler, because you can do everything in Pascal.
Not many people know this, but this can be done with FPC and the generated code is often better than you or me or Fred can do ourselves. So in this case it is not about the algorithm, but about compiler options and the way the rtl is built.
The make script for FPC has an OPT="<whatever option you want>" for that.
« Last Edit: November 05, 2021, 06:10:46 pm by Thaddy »
Specialize a type, not a var.

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Add arrays into one ?
« Reply #5 on: November 05, 2021, 06:14:50 pm »
About this : cfloat = 0.3456 ;. declare it as a (global) const. This will help the compiler and does not take up stack space.
Specialize a type, not a var.

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: Add arrays into one ?
« Reply #6 on: November 05, 2021, 06:35:38 pm »
About this : cfloat = 0.3456 ;. declare it as a (global) const. This will help the compiler and does not take up stack space.

Ok but this was only to show the thing, does it exist optimization too for multiplication, like done with concact() for addition ?
« Last Edit: November 05, 2021, 06:47:22 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Add arrays into one ?
« Reply #7 on: November 05, 2021, 07:36:19 pm »

I shall leave the optimisations to the fp experts here, for I am a beginner in fp.
But I do note that things like
Code: Pascal  [Select][+][-]
  1. arr[i]+=arr2[i];
  2. arr[i]*=arr2[i];


do not work with build 3.2.2 or 3.2.0.
(Win 10)


Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Add arrays into one ?
« Reply #8 on: November 05, 2021, 07:49:09 pm »

I shall leave the optimisations to the fp experts here, for I am a beginner in fp.
But I do note that things like
Code: Pascal  [Select][+][-]
  1. arr[i]+=arr2[i];
  2. arr[i]*=arr2[i];


do not work with build 3.2.2 or 3.2.0.
(Win 10)
Those C'sms are strongly discouraged. Those crept in a long time ago, but even the devs never use it.
(Never matured and the resulting code is even slower in some cases)
If you are a beginner: do not use those, but write out the equivalent in true Pascal code.
So  a:= a+b instead of a:+=b.
Convincing example: the compiler sources and the rtl do not contain that filth.
Marco commented about this this week.
That said: can you give a compilable example that "does not work"? Because at first glance it should.
« Last Edit: November 05, 2021, 07:54:45 pm by Thaddy »
Specialize a type, not a var.

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: Add arrays into one ?
« Reply #9 on: November 05, 2021, 07:52:07 pm »
Hello Thaddy.

OK, fpc 3.3.1 trunk recompiled using this:

Code: Bash  [Select][+][-]
  1. make all FPC=$COMPILER OPT="-Fl/usr/local/lib -CfAVX2 -dFASTMATH"

I will do some test, it can take some time before result.

Many thanks.

Fre;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Add arrays into one ?
« Reply #10 on: November 05, 2021, 08:43:03 pm »
Ok but this was only to show the thing, does it exist optimization too for multiplication, like done with concact() for addition ?
Yes. the -Cf<XXX> flag will optimze that and more too. You should be able to examine the assembler output.
Specialize a type, not a var.

glorfin

  • Full Member
  • ***
  • Posts: 148
  • LMath supporter
Re: Add arrays into one ?
« Reply #11 on: November 05, 2021, 09:03:05 pm »
But, Thaddy, concat does not do what the topicstarter asks for. It really concatenates arrays, adding a second to the end of a first etc. And "+" with {$modeswitch arrayoperators+} does the same.
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. var
  3.   Arr1 : array of single = (1.0,2.0,3.0);
  4.   Arr2 : array of single = (4.0,5.0,6.0);
  5.   Arr0 : array of single;
  6.   I:integer;
  7. begin
  8.   Arr0 := concat(Arr1,Arr2);
  9.   for I := 0 to high(Arr0) do
  10.     writeln(Arr0[I]);
  11.   readln;
  12. end.
  13.  
Output:
1.000000000E+00
 2.000000000E+00
 3.000000000E+00
 4.000000000E+00
 5.000000000E+00
 6.000000000E+00

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Add arrays into one ?
« Reply #12 on: November 05, 2021, 10:06:42 pm »
This may be marginally faster than Fred's "classical" way of adding array elements:
Code: Pascal  [Select][+][-]
  1. program AddArrays;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Types;
  7.  
  8. var
  9.   arrSum, arr1, arr2, arr3: TDoubleDynArray;
  10.   d: Double;
  11.  
  12.   function GetArraySum(a1, a2, a3: TDoubleDynArray): TDoubleDynArray;
  13.   var
  14.     arrLen: SizeInt;
  15.     i: Integer;
  16.     d: Double;
  17.   begin
  18.     Result := Nil;
  19.     arrLen := Length(a1);
  20.     if (Length(a2) <> arrLen) or (Length(a3) <> arrLen) then
  21.       Exit;
  22.     SetLength(Result, arrLen);
  23.     Move(a1[0], Result[0], arrLen * SizeOf(Double));
  24.     for i := 0 to High(Result) do
  25.       Result[i] := Result[i] + a2[i] + a3[i];
  26.   end;
  27.  
  28. begin
  29.   arr1 := [0, 1.1, 2.2, 3.3];
  30.   arr2 := [10.4, 11.5, 12.6, 13.7];
  31.   arr3 := [100.8, 101.9, 102.1, 103];
  32.   arrSum := GetArraySum(arr1, arr2, arr3);
  33.   for d in arrSum do
  34.     Write(d:4:1,' ');
  35. end.

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Add arrays into one ?
« Reply #13 on: November 05, 2021, 10:32:35 pm »
On second thoughts (I have not timed any of these routines) I think what I showed is probably slower than your method, since it is basically the same, but with an added memory move.
I think you should look for an optimised way to add (or in your second case, multiply) several floating point values.
« Last Edit: November 05, 2021, 10:34:53 pm by howardpc »

Fred vS

  • Hero Member
  • *****
  • Posts: 3158
    • StrumPract is the musicians best friend
Re: Add arrays into one ?
« Reply #14 on: November 05, 2021, 11:37:42 pm »
I think you should look for an optimised way to add (or in your second case, multiply) several floating point values.

Hum, it is basically to goal of the initial question.
It seems that, by code, not lot of gain in speed can be expected.

@Thaddy, do you think that -CfAVX2 -dFASTMATH compiler-optimization could have a real impact in the "classical" code of initial post ( if you agree to read it, of course )?
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

 

TinyPortal © 2005-2018