Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GaussianProcessTuning/ILNumerics.2.14.4735.573/Functions/builtin/mod.cs @ 11194

Last change on this file since 11194 was 9102, checked in by gkronber, 12 years ago

#1967: ILNumerics source for experimentation

File size: 212.1 KB
Line 
1///
2///    This file is part of ILNumerics Community Edition.
3///
4///    ILNumerics Community Edition - high performance computing for applications.
5///    Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
6///
7///    ILNumerics Community Edition is free software: you can redistribute it and/or modify
8///    it under the terms of the GNU General Public License version 3 as published by
9///    the Free Software Foundation.
10///
11///    ILNumerics Community Edition is distributed in the hope that it will be useful,
12///    but WITHOUT ANY WARRANTY; without even the implied warranty of
13///    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14///    GNU General Public License for more details.
15///
16///    You should have received a copy of the GNU General Public License
17///    along with ILNumerics Community Edition. See the file License.txt in the root
18///    of your distribution package. If not, see <http://www.gnu.org/licenses/>.
19///
20///    In addition this software uses the following components and/or licenses:
21///
22///    =================================================================================
23///    The Open Toolkit Library License
24///   
25///    Copyright (c) 2006 - 2009 the Open Toolkit library.
26///   
27///    Permission is hereby granted, free of charge, to any person obtaining a copy
28///    of this software and associated documentation files (the "Software"), to deal
29///    in the Software without restriction, including without limitation the rights to
30///    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
31///    the Software, and to permit persons to whom the Software is furnished to do
32///    so, subject to the following conditions:
33///
34///    The above copyright notice and this permission notice shall be included in all
35///    copies or substantial portions of the Software.
36///
37///    =================================================================================
38///   
39
40using System;
41using ILNumerics;
42using ILNumerics.Misc;
43using ILNumerics.Storage;
44using ILNumerics.Native;
45using ILNumerics.Exceptions;
46
47
48
49namespace ILNumerics {
50
51    public partial class ILMath {
52
53
54
55
56#region HYCALPER AUTO GENERATED CODE
57
58        /// <summary>Modulus of array elements</summary>
59        /// <param name="A">Input array A</param>
60        /// <param name="B">Input array B</param>
61        /// <returns>New array with result of elementwise modulus operation</returns>
62        /// <remarks><para>On empty input an empty array will be returned.</para>
63        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
64        /// other array.</para>
65        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
66        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
67        /// can be used to replace the (costly) repmat function for most binary operators.</para>
68        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
69        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
70        public unsafe static ILRetArray<Int64>  mod(ILInArray<Int64> A, ILInArray<Int64> B) {
71            using (ILScope.Enter(A,B)) {
72                int outLen;
73                BinOpItMode mode;
74                Int64 [] retArr;
75                Int64 [] arrA = A.GetArrayForRead();
76                Int64[] arrB = B.GetArrayForRead();
77                ILSize outDims;
78                #region determine operation mode
79                if (A.IsScalar) {
80                    outDims = B.Size;
81                    if (B.IsScalar) {
82                       
83                        return new  ILRetArray<Int64> (new  Int64 [1]{ saturateInt64 (A.GetValue(0)  % (double) B.GetValue(0))}, A.Size);
84                    } else if (B.IsEmpty) {
85                        return  ILRetArray<Int64>.empty(outDims);
86                    } else {
87                        outLen = outDims.NumberOfElements;
88                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
89                            retArr = ILMemoryPool.Pool.New< Int64 > (outLen);
90                            mode = BinOpItMode.SAN;
91                        } else {
92                            mode = BinOpItMode.SAI;
93                        }
94                    }
95                } else {
96                    outDims = A.Size;
97                    if (B.IsScalar) {
98                        if (A.IsEmpty) {
99                            return  ILRetArray<Int64>.empty(A.Size); 
100                        }
101                        outLen = A.S.NumberOfElements;
102                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
103                            retArr = ILMemoryPool.Pool.New< Int64 > (outLen);
104                            mode = BinOpItMode.ASN;
105                        } else {
106                            mode = BinOpItMode.ASI;
107                        }
108                    } else {
109                        // array + array
110                        if (!A.Size.IsSameSize(B.Size)) {
111                            return  modEx(A,B);
112                        }
113                        outLen = A.S.NumberOfElements;
114                        if (A.TryGetStorage4InplaceOp(out retArr))
115                            mode  = BinOpItMode.AAIA;
116                        else if (B.TryGetStorage4InplaceOp(out retArr))
117                            mode = BinOpItMode.AAIB;
118                        else {
119                            retArr = ILMemoryPool.Pool.New< Int64 > (outLen);
120                            mode = BinOpItMode.AAN;
121                        }
122                    }
123                }
124                #endregion
125                ILDenseStorage<Int64> retStorage = new ILDenseStorage<Int64>(retArr, outDims);
126                int i = 0, workerCount = 1;
127                Action<object> worker = data => {
128                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
129                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
130                    Int64* cp = (Int64*)range.Item5 + range.Item1;
131                    Int64 scalar;
132                    int j = range.Item2;
133                    #region loops
134                    switch (mode) {
135                        case BinOpItMode.AAIA:
136                           Int64* bp = ((Int64*)range.Item4 + range.Item1);
137                            while (j > 20) {
138                                cp[0] =  saturateInt64 (cp[0]  % (double) bp[0]);
139                                cp[1] =  saturateInt64 (cp[1]  % (double) bp[1]);
140                                cp[2] =  saturateInt64 (cp[2]  % (double) bp[2]);
141                                cp[3] =  saturateInt64 (cp[3]  % (double) bp[3]);
142                                cp[4] =  saturateInt64 (cp[4]  % (double) bp[4]);
143                                cp[5] =  saturateInt64 (cp[5]  % (double) bp[5]);
144                                cp[6] =  saturateInt64 (cp[6]  % (double) bp[6]);
145                                cp[7] =  saturateInt64 (cp[7]  % (double) bp[7]);
146                                cp[8] =  saturateInt64 (cp[8]  % (double) bp[8]);
147                                cp[9] =  saturateInt64 (cp[9]  % (double) bp[9]);
148                                cp[10] =  saturateInt64 (cp[10]  % (double) bp[10]);
149                                cp[11] =  saturateInt64 (cp[11]  % (double) bp[11]);
150                                cp[12] =  saturateInt64 (cp[12]  % (double) bp[12]);
151                                cp[13] =  saturateInt64 (cp[13]  % (double) bp[13]);
152                                cp[14] =  saturateInt64 (cp[14]  % (double) bp[14]);
153                                cp[15] =  saturateInt64 (cp[15]  % (double) bp[15]);
154                                cp[16] =  saturateInt64 (cp[16]  % (double) bp[16]);
155                                cp[17] =  saturateInt64 (cp[17]  % (double) bp[17]);
156                                cp[18] =  saturateInt64 (cp[18]  % (double) bp[18]);
157                                cp[19] =  saturateInt64 (cp[19]  % (double) bp[19]);
158                                cp[20] =  saturateInt64 (cp[20]  % (double) bp[20]);
159                                cp += 21; bp += 21; j -= 21;
160                            }
161                            while (j --> 0) {
162                               
163                                *cp =  saturateInt64 (*cp  % (double) *bp);
164                                cp++; bp++;
165                            }
166                            break;
167                        case BinOpItMode.AAIB:
168                           Int64* ap = ((Int64*)range.Item3 + range.Item1);
169                            while (j > 20) {
170                               
171                                cp[0] =  saturateInt64 (ap[0]  % (double) cp[0]);
172                                cp[1] =  saturateInt64 (ap[1]  % (double) cp[1]);
173                                cp[2] =  saturateInt64 (ap[2]  % (double) cp[2]);
174                                cp[3] =  saturateInt64 (ap[3]  % (double) cp[3]);
175                                cp[4] =  saturateInt64 (ap[4]  % (double) cp[4]);
176                                cp[5] =  saturateInt64 (ap[5]  % (double) cp[5]);
177                                cp[6] =  saturateInt64 (ap[6]  % (double) cp[6]);
178                                cp[7] =  saturateInt64 (ap[7]  % (double) cp[7]);
179                                cp[8] =  saturateInt64 (ap[8]  % (double) cp[8]);
180                                cp[9] =  saturateInt64 (ap[9]  % (double) cp[9]);
181                                cp[10] =  saturateInt64 (ap[10]  % (double) cp[10]);
182                                cp[11] =  saturateInt64 (ap[11]  % (double) cp[11]);
183                                cp[12] =  saturateInt64 (ap[12]  % (double) cp[12]);
184                                cp[13] =  saturateInt64 (ap[13]  % (double) cp[13]);
185                                cp[14] =  saturateInt64 (ap[14]  % (double) cp[14]);
186                                cp[15] =  saturateInt64 (ap[15]  % (double) cp[15]);
187                                cp[16] =  saturateInt64 (ap[16]  % (double) cp[16]);
188                                cp[17] =  saturateInt64 (ap[17]  % (double) cp[17]);
189                                cp[18] =  saturateInt64 (ap[18]  % (double) cp[18]);
190                                cp[19] =  saturateInt64 (ap[19]  % (double) cp[19]);
191                                cp[20] =  saturateInt64 (ap[20]  % (double) cp[20]);
192                                ap += 21; cp += 21; j -= 21;
193                            }
194                            while (j --> 0) {
195                               
196                                *cp =  saturateInt64 (*ap  % (double) *cp);
197                                ap++; cp++;
198                            }
199                            break;
200                        case BinOpItMode.AAN:
201                            ap = ((Int64*)range.Item3 + range.Item1);
202                            bp = ((Int64*)range.Item4 + range.Item1);
203                            while (j > 20) {
204                               
205                                cp[0] =  saturateInt64 (ap[0]  % (double) bp[0]);
206                                cp[1] =  saturateInt64 (ap[1]  % (double) bp[1]);
207                                cp[2] =  saturateInt64 (ap[2]  % (double) bp[2]);
208                                cp[3] =  saturateInt64 (ap[3]  % (double) bp[3]);
209                                cp[4] =  saturateInt64 (ap[4]  % (double) bp[4]);
210                                cp[5] =  saturateInt64 (ap[5]  % (double) bp[5]);
211                                cp[6] =  saturateInt64 (ap[6]  % (double) bp[6]);
212                                cp[7] =  saturateInt64 (ap[7]  % (double) bp[7]);
213                                cp[8] =  saturateInt64 (ap[8]  % (double) bp[8]);
214                                cp[9] =  saturateInt64 (ap[9]  % (double) bp[9]);
215                                cp[10] =  saturateInt64 (ap[10]  % (double) bp[10]);
216                                cp[11] =  saturateInt64 (ap[11]  % (double) bp[11]);
217                                cp[12] =  saturateInt64 (ap[12]  % (double) bp[12]);
218                                cp[13] =  saturateInt64 (ap[13]  % (double) bp[13]);
219                                cp[14] =  saturateInt64 (ap[14]  % (double) bp[14]);
220                                cp[15] =  saturateInt64 (ap[15]  % (double) bp[15]);
221                                cp[16] =  saturateInt64 (ap[16]  % (double) bp[16]);
222                                cp[17] =  saturateInt64 (ap[17]  % (double) bp[17]);
223                                cp[18] =  saturateInt64 (ap[18]  % (double) bp[18]);
224                                cp[19] =  saturateInt64 (ap[19]  % (double) bp[19]);
225                                cp[20] =  saturateInt64 (ap[20]  % (double) bp[20]);
226                                ap+=21; bp+=21; cp+=21; j-=21;
227                            }
228                            while (j --> 0) {
229                               
230                                *cp =  saturateInt64 (*ap  % (double) *bp);
231                                ap++; bp++; cp++;
232                            }
233                            break;
234                        case BinOpItMode.ASI:
235                            scalar = *((Int64*)range.Item4);
236                            while (j > 20) {
237                               
238                                cp[0] =  saturateInt64 (cp[0]  % (double) scalar);
239                                cp[1] =  saturateInt64 (cp[1]  % (double) scalar);
240                                cp[2] =  saturateInt64 (cp[2]  % (double) scalar);
241                                cp[3] =  saturateInt64 (cp[3]  % (double) scalar);
242                                cp[4] =  saturateInt64 (cp[4]  % (double) scalar);
243                                cp[5] =  saturateInt64 (cp[5]  % (double) scalar);
244                                cp[6] =  saturateInt64 (cp[6]  % (double) scalar);
245                                cp[7] =  saturateInt64 (cp[7]  % (double) scalar);
246                                cp[8] =  saturateInt64 (cp[8]  % (double) scalar);
247                                cp[9] =  saturateInt64 (cp[9]  % (double) scalar);
248                                cp[10] =  saturateInt64 (cp[10]  % (double) scalar);
249                                cp[11] =  saturateInt64 (cp[11]  % (double) scalar);
250                                cp[12] =  saturateInt64 (cp[12]  % (double) scalar);
251                                cp[13] =  saturateInt64 (cp[13]  % (double) scalar);
252                                cp[14] =  saturateInt64 (cp[14]  % (double) scalar);
253                                cp[15] =  saturateInt64 (cp[15]  % (double) scalar);
254                                cp[16] =  saturateInt64 (cp[16]  % (double) scalar);
255                                cp[17] =  saturateInt64 (cp[17]  % (double) scalar);
256                                cp[18] =  saturateInt64 (cp[18]  % (double) scalar);
257                                cp[19] =  saturateInt64 (cp[19]  % (double) scalar);
258                                cp[20] =  saturateInt64 (cp[20]  % (double) scalar);
259                                cp += 21; j -= 21;
260                            }
261                            while (j --> 0) {
262                               
263                                *cp =  saturateInt64 (*cp  % (double) scalar);
264                                cp++;
265                            }
266                            break;
267                        case BinOpItMode.ASN:
268                            ap = ((Int64*)range.Item3 + range.Item1);
269                            scalar = *((Int64*)range.Item4);
270                            while (j > 20) {
271                               
272                                cp[0] =  saturateInt64 (ap[0]  % (double) scalar);
273                                cp[1] =  saturateInt64 (ap[1]  % (double) scalar);
274                                cp[2] =  saturateInt64 (ap[2]  % (double) scalar);
275                                cp[3] =  saturateInt64 (ap[3]  % (double) scalar);
276                                cp[4] =  saturateInt64 (ap[4]  % (double) scalar);
277                                cp[5] =  saturateInt64 (ap[5]  % (double) scalar);
278                                cp[6] =  saturateInt64 (ap[6]  % (double) scalar);
279                                cp[7] =  saturateInt64 (ap[7]  % (double) scalar);
280                                cp[8] =  saturateInt64 (ap[8]  % (double) scalar);
281                                cp[9] =  saturateInt64 (ap[9]  % (double) scalar);
282                                cp[10] =  saturateInt64 (ap[10]  % (double) scalar);
283                                cp[11] =  saturateInt64 (ap[11]  % (double) scalar);
284                                cp[12] =  saturateInt64 (ap[12]  % (double) scalar);
285                                cp[13] =  saturateInt64 (ap[13]  % (double) scalar);
286                                cp[14] =  saturateInt64 (ap[14]  % (double) scalar);
287                                cp[15] =  saturateInt64 (ap[15]  % (double) scalar);
288                                cp[16] =  saturateInt64 (ap[16]  % (double) scalar);
289                                cp[17] =  saturateInt64 (ap[17]  % (double) scalar);
290                                cp[18] =  saturateInt64 (ap[18]  % (double) scalar);
291                                cp[19] =  saturateInt64 (ap[19]  % (double) scalar);
292                                cp[20] =  saturateInt64 (ap[20]  % (double) scalar);
293                                ap+=21; cp+=21; j -= 21;
294                            }
295                            while (j --> 0) {
296                               
297                                *cp =  saturateInt64 (*ap  % (double) scalar);
298                                ap++; cp++;
299                            }
300                            break;
301                        case BinOpItMode.SAI:
302                            scalar = *((Int64*)range.Item3);
303                            while (j > 20) {
304                               
305                                cp[0] =  saturateInt64 (scalar  % (double) cp[0]);
306                                cp[1] =  saturateInt64 (scalar  % (double) cp[1]);
307                                cp[2] =  saturateInt64 (scalar  % (double) cp[2]);
308                                cp[3] =  saturateInt64 (scalar  % (double) cp[3]);
309                                cp[4] =  saturateInt64 (scalar  % (double) cp[4]);
310                                cp[5] =  saturateInt64 (scalar  % (double) cp[5]);
311                                cp[6] =  saturateInt64 (scalar  % (double) cp[6]);
312                                cp[7] =  saturateInt64 (scalar  % (double) cp[7]);
313                                cp[8] =  saturateInt64 (scalar  % (double) cp[8]);
314                                cp[9] =  saturateInt64 (scalar  % (double) cp[9]);
315                                cp[10] =  saturateInt64 (scalar  % (double) cp[10]);
316                                cp[11] =  saturateInt64 (scalar  % (double) cp[11]);
317                                cp[12] =  saturateInt64 (scalar  % (double) cp[12]);
318                                cp[13] =  saturateInt64 (scalar  % (double) cp[13]);
319                                cp[14] =  saturateInt64 (scalar  % (double) cp[14]);
320                                cp[15] =  saturateInt64 (scalar  % (double) cp[15]);
321                                cp[16] =  saturateInt64 (scalar  % (double) cp[16]);
322                                cp[17] =  saturateInt64 (scalar  % (double) cp[17]);
323                                cp[18] =  saturateInt64 (scalar  % (double) cp[18]);
324                                cp[19] =  saturateInt64 (scalar  % (double) cp[19]);
325                                cp[20] =  saturateInt64 (scalar  % (double) cp[20]);
326                                cp += 21; j -= 21;
327                            }
328                            while (j --> 0) {
329                               
330                                *cp =  saturateInt64 (scalar  % (double) *cp);
331                                cp++;
332                            }
333                            break;
334                        case BinOpItMode.SAN:
335                            scalar = *((Int64*)range.Item3);
336                            bp = ((Int64*)range.Item4 + range.Item1);
337                            while (j > 20) {
338                               
339                                cp[0] =  saturateInt64 (scalar  % (double) bp[0]);
340                                cp[1] =  saturateInt64 (scalar  % (double) bp[1]);
341                                cp[2] =  saturateInt64 (scalar  % (double) bp[2]);
342                                cp[3] =  saturateInt64 (scalar  % (double) bp[3]);
343                                cp[4] =  saturateInt64 (scalar  % (double) bp[4]);
344                                cp[5] =  saturateInt64 (scalar  % (double) bp[5]);
345                                cp[6] =  saturateInt64 (scalar  % (double) bp[6]);
346                                cp[7] =  saturateInt64 (scalar  % (double) bp[7]);
347                                cp[8] =  saturateInt64 (scalar  % (double) bp[8]);
348                                cp[9] =  saturateInt64 (scalar  % (double) bp[9]);
349                                cp[10] =  saturateInt64 (scalar  % (double) bp[10]);
350                                cp[11] =  saturateInt64 (scalar  % (double) bp[11]);
351                                cp[12] =  saturateInt64 (scalar  % (double) bp[12]);
352                                cp[13] =  saturateInt64 (scalar  % (double) bp[13]);
353                                cp[14] =  saturateInt64 (scalar  % (double) bp[14]);
354                                cp[15] =  saturateInt64 (scalar  % (double) bp[15]);
355                                cp[16] =  saturateInt64 (scalar  % (double) bp[16]);
356                                cp[17] =  saturateInt64 (scalar  % (double) bp[17]);
357                                cp[18] =  saturateInt64 (scalar  % (double) bp[18]);
358                                cp[19] =  saturateInt64 (scalar  % (double) bp[19]);
359                                cp[20] =  saturateInt64 (scalar  % (double) bp[20]);
360                                bp+=21; cp+=21; j -= 21;
361                            }
362                            while (j --> 0) {
363                               
364                                *cp =  saturateInt64 (scalar  % (double) *bp);
365                                bp++; cp++;
366                            }
367                            break;
368                        default:
369                            break;
370                    }
371                    #endregion
372                    System.Threading.Interlocked.Decrement(ref workerCount);
373                    //retStorage.PendingEvents.Signal();
374                };
375
376                #region do the work
377                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
378                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
379                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
380                        workItemLength = outLen / workItemCount;
381                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
382                    } else {
383                        workItemLength = outLen / 2;
384                        workItemCount = 2;
385                    }
386                } else {
387                    workItemLength = outLen;
388                    workItemCount = 1;
389                }
390               
391                fixed ( Int64* arrAP = arrA)
392                fixed ( Int64* arrBP = arrB)
393                fixed ( Int64* retArrP = retArr) {
394
395                    for (; i < workItemCount - 1; i++) {
396                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
397                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
398                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
399                        System.Threading.Interlocked.Increment(ref workerCount);
400                        ILThreadPool.QueueUserWorkItem(i, worker, range);
401                    }
402                    // the last (or may the only) chunk is done right here
403                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
404                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
405                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
406
407                    ILThreadPool.Wait4Workers(ref workerCount);
408                }
409
410                #endregion
411                return new  ILRetArray< Int64>(retStorage);
412            }
413        }
414
415        private static unsafe ILRetArray<Int64>  modEx(ILInArray<Int64> A, ILInArray<Int64> B) {
416            //using (ILScope.Enter(A, B)) { we cannot start a new scope here, since this would prevent A and B to be used implace if applicable
417
418                #region parameter checking
419                if (isnull(A) || isnull(B))
420                    return empty<Int64>(ILSize.Empty00);
421                if (A.IsEmpty) {
422                    return empty<Int64>(B.S);
423                } else if (B.IsEmpty) {
424                    return empty<Int64>(A.S);
425                }
426                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
427                //    return add(A,B);
428                int dim = -1;
429                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
430                    if (A.S[l] != B.S[l]) {
431                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
432                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
433                        }
434                        dim = l;
435                    }
436                }
437                if (dim > 1)
438                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
439                dim = -(dim - 1);  // 0 -> 1, 1 -> 0
440                #endregion
441
442                #region parameter preparation
443               
444                Int64[] retArr;
445               
446                Int64[] arrA = A.GetArrayForRead();
447               
448                Int64[] arrB = B.GetArrayForRead();
449                ILSize outDims;
450                BinOptItExMode mode;
451                int workItemMultiplierLenA;
452                int workItemMultiplierLenB;
453                if (A.IsVector) {
454                    outDims = B.S;
455                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
456                        retArr = ILMemoryPool.Pool.New<Int64>(outDims.NumberOfElements);
457                        mode = BinOptItExMode.VAN;
458                    } else {
459                        mode = BinOptItExMode.VAI;
460                    }
461                    workItemMultiplierLenB = outDims[0];
462                    workItemMultiplierLenA = dim;  // 0 for column, 1 for row vector
463                } else if (B.IsVector) {
464                    outDims = A.S;
465                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
466                        retArr = ILMemoryPool.Pool.New<Int64>(outDims.NumberOfElements);
467                        mode = BinOptItExMode.AVN;
468                    } else {
469                        mode = BinOptItExMode.AVI;
470                    }
471                    workItemMultiplierLenB = dim;  // 0 for column, 1 for row vector
472                    workItemMultiplierLenA = outDims[0];
473                } else {
474                    throw new ILArgumentException("A and B must have the same size except for one singleton dimension in either A or B");
475                }
476                int itLen = outDims[0]; // (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
477                #endregion
478
479                #region worker loops definition
480                ILDenseStorage<Int64> retStorage = new ILDenseStorage<Int64>(retArr, outDims);
481                int workerCount = 1;
482                Action<object> worker = data => {
483                    // expects: iStart, iLen, ap, bp, cp
484                    Tuple<int, IntPtr, IntPtr, IntPtr> range =
485                        (Tuple<int, IntPtr, IntPtr, IntPtr>)data;
486                   
487                    Int64* ap;
488                   
489                    Int64* bp;
490                   
491                    Int64* cp;
492                    switch (mode) {
493                        case BinOptItExMode.VAN:
494                            if (dim == 0) {
495                                bp = (Int64*)range.Item3;
496                                cp = (Int64*)range.Item4;
497                                for (int s = 0; s < range.Item1; s++) {
498                                    ap = (Int64*)range.Item2;
499                                    int l = itLen;
500                                    while (l > 10) {
501                                        cp[0] =  saturateInt64 (ap[0]  % (double) bp[0]);
502                                        cp[1] =  saturateInt64 (ap[1]  % (double) bp[1]);
503                                        cp[2] =  saturateInt64 (ap[2]  % (double) bp[2]);
504                                        cp[3] =  saturateInt64 (ap[3]  % (double) bp[3]);
505                                        cp[4] =  saturateInt64 (ap[4]  % (double) bp[4]);
506                                        cp[5] =  saturateInt64 (ap[5]  % (double) bp[5]);
507                                        cp[6] =  saturateInt64 (ap[6]  % (double) bp[6]);
508                                        cp[7] =  saturateInt64 (ap[7]  % (double) bp[7]);
509                                        cp[8] =  saturateInt64 (ap[8]  % (double) bp[8]);
510                                        cp[9] =  saturateInt64 (ap[9]  % (double) bp[9]);
511                                        cp[10] =  saturateInt64 (ap[10]  % (double) bp[10]);
512                                        ap += 11;
513                                        bp += 11;
514                                        cp += 11;
515                                        l -= 11;
516                                    }
517                                    while (l-- > 0) {
518                                        *cp++ =  saturateInt64 (*ap++  % (double) *bp++);
519                                    }
520                                }
521                            } else {
522                                // dim == 1
523                                ap = (Int64*)range.Item2;
524                                bp = (Int64*)range.Item3;
525                                cp = (Int64*)range.Item4;
526                                for (int s = 0; s < range.Item1; s++) {
527                                   Int64 val = *ap++;
528                                    int l = itLen;
529                                    while (l > 10) {
530                                        cp[0] =  saturateInt64 (val  % (double) bp[0]);
531                                        cp[1] =  saturateInt64 (val  % (double) bp[1]);
532                                        cp[2] =  saturateInt64 (val  % (double) bp[2]);
533                                        cp[3] =  saturateInt64 (val  % (double) bp[3]);
534                                        cp[4] =  saturateInt64 (val  % (double) bp[4]);
535                                        cp[5] =  saturateInt64 (val  % (double) bp[5]);
536                                        cp[6] =  saturateInt64 (val  % (double) bp[6]);
537                                        cp[7] =  saturateInt64 (val  % (double) bp[7]);
538                                        cp[8] =  saturateInt64 (val  % (double) bp[8]);
539                                        cp[9] =  saturateInt64 (val  % (double) bp[9]);
540                                        cp[10] =  saturateInt64 (val  % (double) bp[10]);
541                                        bp += 11;
542                                        cp += 11;
543                                        l -= 11;
544                                    }
545                                    while (l-- > 0) {
546                                        *cp++ =  saturateInt64 (val  % (double) *bp++);
547                                    }
548                                }
549                            }
550                            break;
551                        case BinOptItExMode.VAI:
552                            if (dim == 0) {
553                                cp = (Int64*)range.Item4;
554                                for (int s = 0; s < range.Item1; s++) {
555                                    ap = (Int64*)range.Item2;
556                                    int l = itLen;
557                                    while (l > 10) {
558                                        cp[0] =  saturateInt64 (ap[0]  % (double) cp[0]);
559                                        cp[1] =  saturateInt64 (ap[1]  % (double) cp[1]);
560                                        cp[2] =  saturateInt64 (ap[2]  % (double) cp[2]);
561                                        cp[3] =  saturateInt64 (ap[3]  % (double) cp[3]);
562                                        cp[4] =  saturateInt64 (ap[4]  % (double) cp[4]);
563                                        cp[5] =  saturateInt64 (ap[5]  % (double) cp[5]);
564                                        cp[6] =  saturateInt64 (ap[6]  % (double) cp[6]);
565                                        cp[7] =  saturateInt64 (ap[7]  % (double) cp[7]);
566                                        cp[8] =  saturateInt64 (ap[8]  % (double) cp[8]);
567                                        cp[9] =  saturateInt64 (ap[9]  % (double) cp[9]);
568                                        cp[10] =  saturateInt64 (ap[10]  % (double) cp[10]);
569                                        ap += 11;
570                                        cp += 11;
571                                        l -= 11;
572                                    }
573                                    while (l-- > 0) {
574                                        *cp =  saturateInt64 (*ap++  % (double) *cp);
575                                        cp++;
576                                    }
577                                }
578                            } else {
579                                // dim == 1
580                                cp = (Int64*)range.Item4;
581                                ap = (Int64*)range.Item2;
582                                for (int s = 0; s < range.Item1; s++) {
583                                   
584                                    Int64 val = *ap++;
585                                    int l = itLen;
586                                    while (l > 10) {
587                                        cp[0] =  saturateInt64 (val  % (double) cp[0]);
588                                        cp[1] =  saturateInt64 (val  % (double) cp[1]);
589                                        cp[2] =  saturateInt64 (val  % (double) cp[2]);
590                                        cp[3] =  saturateInt64 (val  % (double) cp[3]);
591                                        cp[4] =  saturateInt64 (val  % (double) cp[4]);
592                                        cp[5] =  saturateInt64 (val  % (double) cp[5]);
593                                        cp[6] =  saturateInt64 (val  % (double) cp[6]);
594                                        cp[7] =  saturateInt64 (val  % (double) cp[7]);
595                                        cp[8] =  saturateInt64 (val  % (double) cp[8]);
596                                        cp[9] =  saturateInt64 (val  % (double) cp[9]);
597                                        cp[10] =  saturateInt64 (val  % (double) cp[10]);
598                                        cp += 11;
599                                        l -= 11;
600                                    }
601                                    while (l-- > 0) {
602                                        *cp =  saturateInt64 (val  % (double) *cp);
603                                        cp++;
604                                    }
605                                }
606                            }
607                            break;
608                        case BinOptItExMode.AVN:
609                            if (dim == 0) {
610                                ap = (Int64*)range.Item2;
611                                cp = (Int64*)range.Item4;
612                                for (int s = 0; s < range.Item1; s++) {
613                                    bp = (Int64*)range.Item3;
614                                    int l = itLen;
615                                    while (l > 10) {
616                                        cp[0] =  saturateInt64 (ap[0]  % (double) bp[0]);
617                                        cp[1] =  saturateInt64 (ap[1]  % (double) bp[1]);
618                                        cp[2] =  saturateInt64 (ap[2]  % (double) bp[2]);
619                                        cp[3] =  saturateInt64 (ap[3]  % (double) bp[3]);
620                                        cp[4] =  saturateInt64 (ap[4]  % (double) bp[4]);
621                                        cp[5] =  saturateInt64 (ap[5]  % (double) bp[5]);
622                                        cp[6] =  saturateInt64 (ap[6]  % (double) bp[6]);
623                                        cp[7] =  saturateInt64 (ap[7]  % (double) bp[7]);
624                                        cp[8] =  saturateInt64 (ap[8]  % (double) bp[8]);
625                                        cp[9] =  saturateInt64 (ap[9]  % (double) bp[9]);
626                                        cp[10] =  saturateInt64 (ap[10]  % (double) bp[10]);
627                                        ap += 11;
628                                        bp += 11;
629                                        cp += 11;
630                                        l -= 11;
631                                    }
632                                    while (l-- > 0) {
633                                        *cp =  saturateInt64 (*ap  % (double) *bp);
634                                        ap++;
635                                        bp++;
636                                        cp++;
637                                    }
638                                }
639                            } else {
640                                // dim = 1
641                                ap = (Int64*)range.Item2;
642                                bp = (Int64*)range.Item3;
643                                cp = (Int64*)range.Item4;
644                                for (int s = 0; s < range.Item1; s++) {
645                                   Int64 val = *bp++;
646                                    int l = itLen;
647                                    while (l > 10) {
648                                        cp[0] =  saturateInt64 (ap[0]  % (double) val);
649                                        cp[1] =  saturateInt64 (ap[1]  % (double) val);
650                                        cp[2] =  saturateInt64 (ap[2]  % (double) val);
651                                        cp[3] =  saturateInt64 (ap[3]  % (double) val);
652                                        cp[4] =  saturateInt64 (ap[4]  % (double) val);
653                                        cp[5] =  saturateInt64 (ap[5]  % (double) val);
654                                        cp[6] =  saturateInt64 (ap[6]  % (double) val);
655                                        cp[7] =  saturateInt64 (ap[7]  % (double) val);
656                                        cp[8] =  saturateInt64 (ap[8]  % (double) val);
657                                        cp[9] =  saturateInt64 (ap[9]  % (double) val);
658                                        cp[10] =  saturateInt64 (ap[10]  % (double) val);
659                                        ap += 11;
660                                        cp += 11;
661                                        l -= 11;
662                                    }
663                                    while (l-- > 0) {
664                                        *cp =  saturateInt64 (*ap  % (double) val);
665                                        ap++;
666                                        cp++;
667                                    }
668                                }
669                            }
670                            break;
671                        case BinOptItExMode.AVI:
672                            if (dim == 0) {
673                                cp = (Int64*)range.Item4;
674                                for (int s = 0; s < range.Item1; s++) {
675                                    bp = (Int64*)range.Item3;
676                                    int l = itLen;
677                                    while (l > 10) {
678                                        cp[0] =  saturateInt64 (cp[0]  % (double) bp[0]);
679                                        cp[1] =  saturateInt64 (cp[1]  % (double) bp[1]);
680                                        cp[2] =  saturateInt64 (cp[2]  % (double) bp[2]);
681                                        cp[3] =  saturateInt64 (cp[3]  % (double) bp[3]);
682                                        cp[4] =  saturateInt64 (cp[4]  % (double) bp[4]);
683                                        cp[5] =  saturateInt64 (cp[5]  % (double) bp[5]);
684                                        cp[6] =  saturateInt64 (cp[6]  % (double) bp[6]);
685                                        cp[7] =  saturateInt64 (cp[7]  % (double) bp[7]);
686                                        cp[8] =  saturateInt64 (cp[8]  % (double) bp[8]);
687                                        cp[9] =  saturateInt64 (cp[9]  % (double) bp[9]);
688                                        cp[10] =  saturateInt64 (cp[10]  % (double) bp[10]);
689                                        bp += 11;
690                                        cp += 11;
691                                        l -= 11;
692                                    }
693                                    while (l-- > 0) {
694                                        *cp =  saturateInt64 (*cp  % (double) *bp);
695                                        bp++;
696                                        cp++;
697                                    }
698                                }
699                            } else {
700                                // dim = 1
701                                bp = (Int64*)range.Item3;
702                                cp = (Int64*)range.Item4;
703                                for (int s = 0; s < range.Item1; s++) {
704                                   
705                                    Int64 val = *bp++;
706                                    int l = itLen;
707                                    while (l > 10) {
708                                        cp[0] =  saturateInt64 (cp[0]  % (double) val);
709                                        cp[1] =  saturateInt64 (cp[1]  % (double) val);
710                                        cp[2] =  saturateInt64 (cp[2]  % (double) val);
711                                        cp[3] =  saturateInt64 (cp[3]  % (double) val);
712                                        cp[4] =  saturateInt64 (cp[4]  % (double) val);
713                                        cp[5] =  saturateInt64 (cp[5]  % (double) val);
714                                        cp[6] =  saturateInt64 (cp[6]  % (double) val);
715                                        cp[7] =  saturateInt64 (cp[7]  % (double) val);
716                                        cp[8] =  saturateInt64 (cp[8]  % (double) val);
717                                        cp[9] =  saturateInt64 (cp[9]  % (double) val);
718                                        cp[10] =  saturateInt64 (cp[10]  % (double) val);
719                                        cp += 11;
720                                        l -= 11;
721                                    }
722                                    while (l --> 0) {
723                                        *cp =  saturateInt64 (*cp  % (double) val);
724                                        cp++;
725                                    }
726                                }
727                            }
728                            break;
729                    }
730                    System.Threading.Interlocked.Decrement(ref workerCount);
731                };
732                #endregion
733
734                #region work distribution
735                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
736                if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count
737                    && outDims[1] > 1) {
738                        if (outDims[1] > workItemCount) {
739                        workItemLength = outDims[1] / workItemCount;
740                    } else {
741                        workItemLength = outDims[1] / 2;
742                        workItemCount = 2;
743                    }
744                } else {
745                    workItemLength = outDims[1];
746                    workItemCount = 1;
747                }
748
749                fixed ( Int64* arrAP = arrA)
750                fixed ( Int64* arrBP = arrB)
751                fixed ( Int64* retArrP = retArr) {
752
753                    for (; i < workItemCount - 1; i++) {
754                        Tuple<int, IntPtr, IntPtr, IntPtr> range = new Tuple<int, IntPtr, IntPtr, IntPtr>
755                               (workItemLength
756                               , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
757                               , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
758                               , (IntPtr)(retArrP + i * outDims[0] * workItemLength));
759                        System.Threading.Interlocked.Increment(ref workerCount);
760                        ILThreadPool.QueueUserWorkItem(i, worker, range);
761                    }
762                    // the last (or may the only) chunk is done right here
763                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
764                    worker(new Tuple<int, IntPtr, IntPtr, IntPtr>
765                                (outDims[1] - i * workItemLength
766                                , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
767                                , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
768                                , (IntPtr)(retArrP + i * outDims[0] * workItemLength)));
769
770                    ILThreadPool.Wait4Workers(ref workerCount);
771                }
772                #endregion
773
774                return new ILRetArray<Int64>(retStorage);
775            //}  // no scopes here! it disables implace operations
776        }
777
778        /// <summary>Modulus of array elements</summary>
779        /// <param name="A">Input array A</param>
780        /// <param name="B">Input array B</param>
781        /// <returns>New array with result of elementwise modulus operation</returns>
782        /// <remarks><para>On empty input an empty array will be returned.</para>
783        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
784        /// other array.</para>
785        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
786        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
787        /// can be used to replace the (costly) repmat function for most binary operators.</para>
788        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
789        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
790        public unsafe static ILRetArray<Int32>  mod(ILInArray<Int32> A, ILInArray<Int32> B) {
791            using (ILScope.Enter(A,B)) {
792                int outLen;
793                BinOpItMode mode;
794                Int32 [] retArr;
795                Int32 [] arrA = A.GetArrayForRead();
796                Int32[] arrB = B.GetArrayForRead();
797                ILSize outDims;
798                #region determine operation mode
799                if (A.IsScalar) {
800                    outDims = B.Size;
801                    if (B.IsScalar) {
802                       
803                        return new  ILRetArray<Int32> (new  Int32 [1]{ saturateInt32 (A.GetValue(0)  % (double) B.GetValue(0))}, A.Size);
804                    } else if (B.IsEmpty) {
805                        return  ILRetArray<Int32>.empty(outDims);
806                    } else {
807                        outLen = outDims.NumberOfElements;
808                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
809                            retArr = ILMemoryPool.Pool.New< Int32 > (outLen);
810                            mode = BinOpItMode.SAN;
811                        } else {
812                            mode = BinOpItMode.SAI;
813                        }
814                    }
815                } else {
816                    outDims = A.Size;
817                    if (B.IsScalar) {
818                        if (A.IsEmpty) {
819                            return  ILRetArray<Int32>.empty(A.Size); 
820                        }
821                        outLen = A.S.NumberOfElements;
822                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
823                            retArr = ILMemoryPool.Pool.New< Int32 > (outLen);
824                            mode = BinOpItMode.ASN;
825                        } else {
826                            mode = BinOpItMode.ASI;
827                        }
828                    } else {
829                        // array + array
830                        if (!A.Size.IsSameSize(B.Size)) {
831                            return  modEx(A,B);
832                        }
833                        outLen = A.S.NumberOfElements;
834                        if (A.TryGetStorage4InplaceOp(out retArr))
835                            mode  = BinOpItMode.AAIA;
836                        else if (B.TryGetStorage4InplaceOp(out retArr))
837                            mode = BinOpItMode.AAIB;
838                        else {
839                            retArr = ILMemoryPool.Pool.New< Int32 > (outLen);
840                            mode = BinOpItMode.AAN;
841                        }
842                    }
843                }
844                #endregion
845                ILDenseStorage<Int32> retStorage = new ILDenseStorage<Int32>(retArr, outDims);
846                int i = 0, workerCount = 1;
847                Action<object> worker = data => {
848                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
849                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
850                    Int32* cp = (Int32*)range.Item5 + range.Item1;
851                    Int32 scalar;
852                    int j = range.Item2;
853                    #region loops
854                    switch (mode) {
855                        case BinOpItMode.AAIA:
856                           Int32* bp = ((Int32*)range.Item4 + range.Item1);
857                            while (j > 20) {
858                                cp[0] =  saturateInt32 (cp[0]  % (double) bp[0]);
859                                cp[1] =  saturateInt32 (cp[1]  % (double) bp[1]);
860                                cp[2] =  saturateInt32 (cp[2]  % (double) bp[2]);
861                                cp[3] =  saturateInt32 (cp[3]  % (double) bp[3]);
862                                cp[4] =  saturateInt32 (cp[4]  % (double) bp[4]);
863                                cp[5] =  saturateInt32 (cp[5]  % (double) bp[5]);
864                                cp[6] =  saturateInt32 (cp[6]  % (double) bp[6]);
865                                cp[7] =  saturateInt32 (cp[7]  % (double) bp[7]);
866                                cp[8] =  saturateInt32 (cp[8]  % (double) bp[8]);
867                                cp[9] =  saturateInt32 (cp[9]  % (double) bp[9]);
868                                cp[10] =  saturateInt32 (cp[10]  % (double) bp[10]);
869                                cp[11] =  saturateInt32 (cp[11]  % (double) bp[11]);
870                                cp[12] =  saturateInt32 (cp[12]  % (double) bp[12]);
871                                cp[13] =  saturateInt32 (cp[13]  % (double) bp[13]);
872                                cp[14] =  saturateInt32 (cp[14]  % (double) bp[14]);
873                                cp[15] =  saturateInt32 (cp[15]  % (double) bp[15]);
874                                cp[16] =  saturateInt32 (cp[16]  % (double) bp[16]);
875                                cp[17] =  saturateInt32 (cp[17]  % (double) bp[17]);
876                                cp[18] =  saturateInt32 (cp[18]  % (double) bp[18]);
877                                cp[19] =  saturateInt32 (cp[19]  % (double) bp[19]);
878                                cp[20] =  saturateInt32 (cp[20]  % (double) bp[20]);
879                                cp += 21; bp += 21; j -= 21;
880                            }
881                            while (j --> 0) {
882                               
883                                *cp =  saturateInt32 (*cp  % (double) *bp);
884                                cp++; bp++;
885                            }
886                            break;
887                        case BinOpItMode.AAIB:
888                           Int32* ap = ((Int32*)range.Item3 + range.Item1);
889                            while (j > 20) {
890                               
891                                cp[0] =  saturateInt32 (ap[0]  % (double) cp[0]);
892                                cp[1] =  saturateInt32 (ap[1]  % (double) cp[1]);
893                                cp[2] =  saturateInt32 (ap[2]  % (double) cp[2]);
894                                cp[3] =  saturateInt32 (ap[3]  % (double) cp[3]);
895                                cp[4] =  saturateInt32 (ap[4]  % (double) cp[4]);
896                                cp[5] =  saturateInt32 (ap[5]  % (double) cp[5]);
897                                cp[6] =  saturateInt32 (ap[6]  % (double) cp[6]);
898                                cp[7] =  saturateInt32 (ap[7]  % (double) cp[7]);
899                                cp[8] =  saturateInt32 (ap[8]  % (double) cp[8]);
900                                cp[9] =  saturateInt32 (ap[9]  % (double) cp[9]);
901                                cp[10] =  saturateInt32 (ap[10]  % (double) cp[10]);
902                                cp[11] =  saturateInt32 (ap[11]  % (double) cp[11]);
903                                cp[12] =  saturateInt32 (ap[12]  % (double) cp[12]);
904                                cp[13] =  saturateInt32 (ap[13]  % (double) cp[13]);
905                                cp[14] =  saturateInt32 (ap[14]  % (double) cp[14]);
906                                cp[15] =  saturateInt32 (ap[15]  % (double) cp[15]);
907                                cp[16] =  saturateInt32 (ap[16]  % (double) cp[16]);
908                                cp[17] =  saturateInt32 (ap[17]  % (double) cp[17]);
909                                cp[18] =  saturateInt32 (ap[18]  % (double) cp[18]);
910                                cp[19] =  saturateInt32 (ap[19]  % (double) cp[19]);
911                                cp[20] =  saturateInt32 (ap[20]  % (double) cp[20]);
912                                ap += 21; cp += 21; j -= 21;
913                            }
914                            while (j --> 0) {
915                               
916                                *cp =  saturateInt32 (*ap  % (double) *cp);
917                                ap++; cp++;
918                            }
919                            break;
920                        case BinOpItMode.AAN:
921                            ap = ((Int32*)range.Item3 + range.Item1);
922                            bp = ((Int32*)range.Item4 + range.Item1);
923                            while (j > 20) {
924                               
925                                cp[0] =  saturateInt32 (ap[0]  % (double) bp[0]);
926                                cp[1] =  saturateInt32 (ap[1]  % (double) bp[1]);
927                                cp[2] =  saturateInt32 (ap[2]  % (double) bp[2]);
928                                cp[3] =  saturateInt32 (ap[3]  % (double) bp[3]);
929                                cp[4] =  saturateInt32 (ap[4]  % (double) bp[4]);
930                                cp[5] =  saturateInt32 (ap[5]  % (double) bp[5]);
931                                cp[6] =  saturateInt32 (ap[6]  % (double) bp[6]);
932                                cp[7] =  saturateInt32 (ap[7]  % (double) bp[7]);
933                                cp[8] =  saturateInt32 (ap[8]  % (double) bp[8]);
934                                cp[9] =  saturateInt32 (ap[9]  % (double) bp[9]);
935                                cp[10] =  saturateInt32 (ap[10]  % (double) bp[10]);
936                                cp[11] =  saturateInt32 (ap[11]  % (double) bp[11]);
937                                cp[12] =  saturateInt32 (ap[12]  % (double) bp[12]);
938                                cp[13] =  saturateInt32 (ap[13]  % (double) bp[13]);
939                                cp[14] =  saturateInt32 (ap[14]  % (double) bp[14]);
940                                cp[15] =  saturateInt32 (ap[15]  % (double) bp[15]);
941                                cp[16] =  saturateInt32 (ap[16]  % (double) bp[16]);
942                                cp[17] =  saturateInt32 (ap[17]  % (double) bp[17]);
943                                cp[18] =  saturateInt32 (ap[18]  % (double) bp[18]);
944                                cp[19] =  saturateInt32 (ap[19]  % (double) bp[19]);
945                                cp[20] =  saturateInt32 (ap[20]  % (double) bp[20]);
946                                ap+=21; bp+=21; cp+=21; j-=21;
947                            }
948                            while (j --> 0) {
949                               
950                                *cp =  saturateInt32 (*ap  % (double) *bp);
951                                ap++; bp++; cp++;
952                            }
953                            break;
954                        case BinOpItMode.ASI:
955                            scalar = *((Int32*)range.Item4);
956                            while (j > 20) {
957                               
958                                cp[0] =  saturateInt32 (cp[0]  % (double) scalar);
959                                cp[1] =  saturateInt32 (cp[1]  % (double) scalar);
960                                cp[2] =  saturateInt32 (cp[2]  % (double) scalar);
961                                cp[3] =  saturateInt32 (cp[3]  % (double) scalar);
962                                cp[4] =  saturateInt32 (cp[4]  % (double) scalar);
963                                cp[5] =  saturateInt32 (cp[5]  % (double) scalar);
964                                cp[6] =  saturateInt32 (cp[6]  % (double) scalar);
965                                cp[7] =  saturateInt32 (cp[7]  % (double) scalar);
966                                cp[8] =  saturateInt32 (cp[8]  % (double) scalar);
967                                cp[9] =  saturateInt32 (cp[9]  % (double) scalar);
968                                cp[10] =  saturateInt32 (cp[10]  % (double) scalar);
969                                cp[11] =  saturateInt32 (cp[11]  % (double) scalar);
970                                cp[12] =  saturateInt32 (cp[12]  % (double) scalar);
971                                cp[13] =  saturateInt32 (cp[13]  % (double) scalar);
972                                cp[14] =  saturateInt32 (cp[14]  % (double) scalar);
973                                cp[15] =  saturateInt32 (cp[15]  % (double) scalar);
974                                cp[16] =  saturateInt32 (cp[16]  % (double) scalar);
975                                cp[17] =  saturateInt32 (cp[17]  % (double) scalar);
976                                cp[18] =  saturateInt32 (cp[18]  % (double) scalar);
977                                cp[19] =  saturateInt32 (cp[19]  % (double) scalar);
978                                cp[20] =  saturateInt32 (cp[20]  % (double) scalar);
979                                cp += 21; j -= 21;
980                            }
981                            while (j --> 0) {
982                               
983                                *cp =  saturateInt32 (*cp  % (double) scalar);
984                                cp++;
985                            }
986                            break;
987                        case BinOpItMode.ASN:
988                            ap = ((Int32*)range.Item3 + range.Item1);
989                            scalar = *((Int32*)range.Item4);
990                            while (j > 20) {
991                               
992                                cp[0] =  saturateInt32 (ap[0]  % (double) scalar);
993                                cp[1] =  saturateInt32 (ap[1]  % (double) scalar);
994                                cp[2] =  saturateInt32 (ap[2]  % (double) scalar);
995                                cp[3] =  saturateInt32 (ap[3]  % (double) scalar);
996                                cp[4] =  saturateInt32 (ap[4]  % (double) scalar);
997                                cp[5] =  saturateInt32 (ap[5]  % (double) scalar);
998                                cp[6] =  saturateInt32 (ap[6]  % (double) scalar);
999                                cp[7] =  saturateInt32 (ap[7]  % (double) scalar);
1000                                cp[8] =  saturateInt32 (ap[8]  % (double) scalar);
1001                                cp[9] =  saturateInt32 (ap[9]  % (double) scalar);
1002                                cp[10] =  saturateInt32 (ap[10]  % (double) scalar);
1003                                cp[11] =  saturateInt32 (ap[11]  % (double) scalar);
1004                                cp[12] =  saturateInt32 (ap[12]  % (double) scalar);
1005                                cp[13] =  saturateInt32 (ap[13]  % (double) scalar);
1006                                cp[14] =  saturateInt32 (ap[14]  % (double) scalar);
1007                                cp[15] =  saturateInt32 (ap[15]  % (double) scalar);
1008                                cp[16] =  saturateInt32 (ap[16]  % (double) scalar);
1009                                cp[17] =  saturateInt32 (ap[17]  % (double) scalar);
1010                                cp[18] =  saturateInt32 (ap[18]  % (double) scalar);
1011                                cp[19] =  saturateInt32 (ap[19]  % (double) scalar);
1012                                cp[20] =  saturateInt32 (ap[20]  % (double) scalar);
1013                                ap+=21; cp+=21; j -= 21;
1014                            }
1015                            while (j --> 0) {
1016                               
1017                                *cp =  saturateInt32 (*ap  % (double) scalar);
1018                                ap++; cp++;
1019                            }
1020                            break;
1021                        case BinOpItMode.SAI:
1022                            scalar = *((Int32*)range.Item3);
1023                            while (j > 20) {
1024                               
1025                                cp[0] =  saturateInt32 (scalar  % (double) cp[0]);
1026                                cp[1] =  saturateInt32 (scalar  % (double) cp[1]);
1027                                cp[2] =  saturateInt32 (scalar  % (double) cp[2]);
1028                                cp[3] =  saturateInt32 (scalar  % (double) cp[3]);
1029                                cp[4] =  saturateInt32 (scalar  % (double) cp[4]);
1030                                cp[5] =  saturateInt32 (scalar  % (double) cp[5]);
1031                                cp[6] =  saturateInt32 (scalar  % (double) cp[6]);
1032                                cp[7] =  saturateInt32 (scalar  % (double) cp[7]);
1033                                cp[8] =  saturateInt32 (scalar  % (double) cp[8]);
1034                                cp[9] =  saturateInt32 (scalar  % (double) cp[9]);
1035                                cp[10] =  saturateInt32 (scalar  % (double) cp[10]);
1036                                cp[11] =  saturateInt32 (scalar  % (double) cp[11]);
1037                                cp[12] =  saturateInt32 (scalar  % (double) cp[12]);
1038                                cp[13] =  saturateInt32 (scalar  % (double) cp[13]);
1039                                cp[14] =  saturateInt32 (scalar  % (double) cp[14]);
1040                                cp[15] =  saturateInt32 (scalar  % (double) cp[15]);
1041                                cp[16] =  saturateInt32 (scalar  % (double) cp[16]);
1042                                cp[17] =  saturateInt32 (scalar  % (double) cp[17]);
1043                                cp[18] =  saturateInt32 (scalar  % (double) cp[18]);
1044                                cp[19] =  saturateInt32 (scalar  % (double) cp[19]);
1045                                cp[20] =  saturateInt32 (scalar  % (double) cp[20]);
1046                                cp += 21; j -= 21;
1047                            }
1048                            while (j --> 0) {
1049                               
1050                                *cp =  saturateInt32 (scalar  % (double) *cp);
1051                                cp++;
1052                            }
1053                            break;
1054                        case BinOpItMode.SAN:
1055                            scalar = *((Int32*)range.Item3);
1056                            bp = ((Int32*)range.Item4 + range.Item1);
1057                            while (j > 20) {
1058                               
1059                                cp[0] =  saturateInt32 (scalar  % (double) bp[0]);
1060                                cp[1] =  saturateInt32 (scalar  % (double) bp[1]);
1061                                cp[2] =  saturateInt32 (scalar  % (double) bp[2]);
1062                                cp[3] =  saturateInt32 (scalar  % (double) bp[3]);
1063                                cp[4] =  saturateInt32 (scalar  % (double) bp[4]);
1064                                cp[5] =  saturateInt32 (scalar  % (double) bp[5]);
1065                                cp[6] =  saturateInt32 (scalar  % (double) bp[6]);
1066                                cp[7] =  saturateInt32 (scalar  % (double) bp[7]);
1067                                cp[8] =  saturateInt32 (scalar  % (double) bp[8]);
1068                                cp[9] =  saturateInt32 (scalar  % (double) bp[9]);
1069                                cp[10] =  saturateInt32 (scalar  % (double) bp[10]);
1070                                cp[11] =  saturateInt32 (scalar  % (double) bp[11]);
1071                                cp[12] =  saturateInt32 (scalar  % (double) bp[12]);
1072                                cp[13] =  saturateInt32 (scalar  % (double) bp[13]);
1073                                cp[14] =  saturateInt32 (scalar  % (double) bp[14]);
1074                                cp[15] =  saturateInt32 (scalar  % (double) bp[15]);
1075                                cp[16] =  saturateInt32 (scalar  % (double) bp[16]);
1076                                cp[17] =  saturateInt32 (scalar  % (double) bp[17]);
1077                                cp[18] =  saturateInt32 (scalar  % (double) bp[18]);
1078                                cp[19] =  saturateInt32 (scalar  % (double) bp[19]);
1079                                cp[20] =  saturateInt32 (scalar  % (double) bp[20]);
1080                                bp+=21; cp+=21; j -= 21;
1081                            }
1082                            while (j --> 0) {
1083                               
1084                                *cp =  saturateInt32 (scalar  % (double) *bp);
1085                                bp++; cp++;
1086                            }
1087                            break;
1088                        default:
1089                            break;
1090                    }
1091                    #endregion
1092                    System.Threading.Interlocked.Decrement(ref workerCount);
1093                    //retStorage.PendingEvents.Signal();
1094                };
1095
1096                #region do the work
1097                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
1098                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
1099                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
1100                        workItemLength = outLen / workItemCount;
1101                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
1102                    } else {
1103                        workItemLength = outLen / 2;
1104                        workItemCount = 2;
1105                    }
1106                } else {
1107                    workItemLength = outLen;
1108                    workItemCount = 1;
1109                }
1110               
1111                fixed ( Int32* arrAP = arrA)
1112                fixed ( Int32* arrBP = arrB)
1113                fixed ( Int32* retArrP = retArr) {
1114
1115                    for (; i < workItemCount - 1; i++) {
1116                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
1117                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
1118                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
1119                        System.Threading.Interlocked.Increment(ref workerCount);
1120                        ILThreadPool.QueueUserWorkItem(i, worker, range);
1121                    }
1122                    // the last (or may the only) chunk is done right here
1123                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
1124                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
1125                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
1126
1127                    ILThreadPool.Wait4Workers(ref workerCount);
1128                }
1129
1130                #endregion
1131                return new  ILRetArray< Int32>(retStorage);
1132            }
1133        }
1134
1135        private static unsafe ILRetArray<Int32>  modEx(ILInArray<Int32> A, ILInArray<Int32> B) {
1136            //using (ILScope.Enter(A, B)) { we cannot start a new scope here, since this would prevent A and B to be used implace if applicable
1137
1138                #region parameter checking
1139                if (isnull(A) || isnull(B))
1140                    return empty<Int32>(ILSize.Empty00);
1141                if (A.IsEmpty) {
1142                    return empty<Int32>(B.S);
1143                } else if (B.IsEmpty) {
1144                    return empty<Int32>(A.S);
1145                }
1146                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
1147                //    return add(A,B);
1148                int dim = -1;
1149                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
1150                    if (A.S[l] != B.S[l]) {
1151                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
1152                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
1153                        }
1154                        dim = l;
1155                    }
1156                }
1157                if (dim > 1)
1158                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
1159                dim = -(dim - 1);  // 0 -> 1, 1 -> 0
1160                #endregion
1161
1162                #region parameter preparation
1163               
1164                Int32[] retArr;
1165               
1166                Int32[] arrA = A.GetArrayForRead();
1167               
1168                Int32[] arrB = B.GetArrayForRead();
1169                ILSize outDims;
1170                BinOptItExMode mode;
1171                int workItemMultiplierLenA;
1172                int workItemMultiplierLenB;
1173                if (A.IsVector) {
1174                    outDims = B.S;
1175                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
1176                        retArr = ILMemoryPool.Pool.New<Int32>(outDims.NumberOfElements);
1177                        mode = BinOptItExMode.VAN;
1178                    } else {
1179                        mode = BinOptItExMode.VAI;
1180                    }
1181                    workItemMultiplierLenB = outDims[0];
1182                    workItemMultiplierLenA = dim;  // 0 for column, 1 for row vector
1183                } else if (B.IsVector) {
1184                    outDims = A.S;
1185                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
1186                        retArr = ILMemoryPool.Pool.New<Int32>(outDims.NumberOfElements);
1187                        mode = BinOptItExMode.AVN;
1188                    } else {
1189                        mode = BinOptItExMode.AVI;
1190                    }
1191                    workItemMultiplierLenB = dim;  // 0 for column, 1 for row vector
1192                    workItemMultiplierLenA = outDims[0];
1193                } else {
1194                    throw new ILArgumentException("A and B must have the same size except for one singleton dimension in either A or B");
1195                }
1196                int itLen = outDims[0]; // (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
1197                #endregion
1198
1199                #region worker loops definition
1200                ILDenseStorage<Int32> retStorage = new ILDenseStorage<Int32>(retArr, outDims);
1201                int workerCount = 1;
1202                Action<object> worker = data => {
1203                    // expects: iStart, iLen, ap, bp, cp
1204                    Tuple<int, IntPtr, IntPtr, IntPtr> range =
1205                        (Tuple<int, IntPtr, IntPtr, IntPtr>)data;
1206                   
1207                    Int32* ap;
1208                   
1209                    Int32* bp;
1210                   
1211                    Int32* cp;
1212                    switch (mode) {
1213                        case BinOptItExMode.VAN:
1214                            if (dim == 0) {
1215                                bp = (Int32*)range.Item3;
1216                                cp = (Int32*)range.Item4;
1217                                for (int s = 0; s < range.Item1; s++) {
1218                                    ap = (Int32*)range.Item2;
1219                                    int l = itLen;
1220                                    while (l > 10) {
1221                                        cp[0] =  saturateInt32 (ap[0]  % (double) bp[0]);
1222                                        cp[1] =  saturateInt32 (ap[1]  % (double) bp[1]);
1223                                        cp[2] =  saturateInt32 (ap[2]  % (double) bp[2]);
1224                                        cp[3] =  saturateInt32 (ap[3]  % (double) bp[3]);
1225                                        cp[4] =  saturateInt32 (ap[4]  % (double) bp[4]);
1226                                        cp[5] =  saturateInt32 (ap[5]  % (double) bp[5]);
1227                                        cp[6] =  saturateInt32 (ap[6]  % (double) bp[6]);
1228                                        cp[7] =  saturateInt32 (ap[7]  % (double) bp[7]);
1229                                        cp[8] =  saturateInt32 (ap[8]  % (double) bp[8]);
1230                                        cp[9] =  saturateInt32 (ap[9]  % (double) bp[9]);
1231                                        cp[10] =  saturateInt32 (ap[10]  % (double) bp[10]);
1232                                        ap += 11;
1233                                        bp += 11;
1234                                        cp += 11;
1235                                        l -= 11;
1236                                    }
1237                                    while (l-- > 0) {
1238                                        *cp++ =  saturateInt32 (*ap++  % (double) *bp++);
1239                                    }
1240                                }
1241                            } else {
1242                                // dim == 1
1243                                ap = (Int32*)range.Item2;
1244                                bp = (Int32*)range.Item3;
1245                                cp = (Int32*)range.Item4;
1246                                for (int s = 0; s < range.Item1; s++) {
1247                                   Int32 val = *ap++;
1248                                    int l = itLen;
1249                                    while (l > 10) {
1250                                        cp[0] =  saturateInt32 (val  % (double) bp[0]);
1251                                        cp[1] =  saturateInt32 (val  % (double) bp[1]);
1252                                        cp[2] =  saturateInt32 (val  % (double) bp[2]);
1253                                        cp[3] =  saturateInt32 (val  % (double) bp[3]);
1254                                        cp[4] =  saturateInt32 (val  % (double) bp[4]);
1255                                        cp[5] =  saturateInt32 (val  % (double) bp[5]);
1256                                        cp[6] =  saturateInt32 (val  % (double) bp[6]);
1257                                        cp[7] =  saturateInt32 (val  % (double) bp[7]);
1258                                        cp[8] =  saturateInt32 (val  % (double) bp[8]);
1259                                        cp[9] =  saturateInt32 (val  % (double) bp[9]);
1260                                        cp[10] =  saturateInt32 (val  % (double) bp[10]);
1261                                        bp += 11;
1262                                        cp += 11;
1263                                        l -= 11;
1264                                    }
1265                                    while (l-- > 0) {
1266                                        *cp++ =  saturateInt32 (val  % (double) *bp++);
1267                                    }
1268                                }
1269                            }
1270                            break;
1271                        case BinOptItExMode.VAI:
1272                            if (dim == 0) {
1273                                cp = (Int32*)range.Item4;
1274                                for (int s = 0; s < range.Item1; s++) {
1275                                    ap = (Int32*)range.Item2;
1276                                    int l = itLen;
1277                                    while (l > 10) {
1278                                        cp[0] =  saturateInt32 (ap[0]  % (double) cp[0]);
1279                                        cp[1] =  saturateInt32 (ap[1]  % (double) cp[1]);
1280                                        cp[2] =  saturateInt32 (ap[2]  % (double) cp[2]);
1281                                        cp[3] =  saturateInt32 (ap[3]  % (double) cp[3]);
1282                                        cp[4] =  saturateInt32 (ap[4]  % (double) cp[4]);
1283                                        cp[5] =  saturateInt32 (ap[5]  % (double) cp[5]);
1284                                        cp[6] =  saturateInt32 (ap[6]  % (double) cp[6]);
1285                                        cp[7] =  saturateInt32 (ap[7]  % (double) cp[7]);
1286                                        cp[8] =  saturateInt32 (ap[8]  % (double) cp[8]);
1287                                        cp[9] =  saturateInt32 (ap[9]  % (double) cp[9]);
1288                                        cp[10] =  saturateInt32 (ap[10]  % (double) cp[10]);
1289                                        ap += 11;
1290                                        cp += 11;
1291                                        l -= 11;
1292                                    }
1293                                    while (l-- > 0) {
1294                                        *cp =  saturateInt32 (*ap++  % (double) *cp);
1295                                        cp++;
1296                                    }
1297                                }
1298                            } else {
1299                                // dim == 1
1300                                cp = (Int32*)range.Item4;
1301                                ap = (Int32*)range.Item2;
1302                                for (int s = 0; s < range.Item1; s++) {
1303                                   
1304                                    Int32 val = *ap++;
1305                                    int l = itLen;
1306                                    while (l > 10) {
1307                                        cp[0] =  saturateInt32 (val  % (double) cp[0]);
1308                                        cp[1] =  saturateInt32 (val  % (double) cp[1]);
1309                                        cp[2] =  saturateInt32 (val  % (double) cp[2]);
1310                                        cp[3] =  saturateInt32 (val  % (double) cp[3]);
1311                                        cp[4] =  saturateInt32 (val  % (double) cp[4]);
1312                                        cp[5] =  saturateInt32 (val  % (double) cp[5]);
1313                                        cp[6] =  saturateInt32 (val  % (double) cp[6]);
1314                                        cp[7] =  saturateInt32 (val  % (double) cp[7]);
1315                                        cp[8] =  saturateInt32 (val  % (double) cp[8]);
1316                                        cp[9] =  saturateInt32 (val  % (double) cp[9]);
1317                                        cp[10] =  saturateInt32 (val  % (double) cp[10]);
1318                                        cp += 11;
1319                                        l -= 11;
1320                                    }
1321                                    while (l-- > 0) {
1322                                        *cp =  saturateInt32 (val  % (double) *cp);
1323                                        cp++;
1324                                    }
1325                                }
1326                            }
1327                            break;
1328                        case BinOptItExMode.AVN:
1329                            if (dim == 0) {
1330                                ap = (Int32*)range.Item2;
1331                                cp = (Int32*)range.Item4;
1332                                for (int s = 0; s < range.Item1; s++) {
1333                                    bp = (Int32*)range.Item3;
1334                                    int l = itLen;
1335                                    while (l > 10) {
1336                                        cp[0] =  saturateInt32 (ap[0]  % (double) bp[0]);
1337                                        cp[1] =  saturateInt32 (ap[1]  % (double) bp[1]);
1338                                        cp[2] =  saturateInt32 (ap[2]  % (double) bp[2]);
1339                                        cp[3] =  saturateInt32 (ap[3]  % (double) bp[3]);
1340                                        cp[4] =  saturateInt32 (ap[4]  % (double) bp[4]);
1341                                        cp[5] =  saturateInt32 (ap[5]  % (double) bp[5]);
1342                                        cp[6] =  saturateInt32 (ap[6]  % (double) bp[6]);
1343                                        cp[7] =  saturateInt32 (ap[7]  % (double) bp[7]);
1344                                        cp[8] =  saturateInt32 (ap[8]  % (double) bp[8]);
1345                                        cp[9] =  saturateInt32 (ap[9]  % (double) bp[9]);
1346                                        cp[10] =  saturateInt32 (ap[10]  % (double) bp[10]);
1347                                        ap += 11;
1348                                        bp += 11;
1349                                        cp += 11;
1350                                        l -= 11;
1351                                    }
1352                                    while (l-- > 0) {
1353                                        *cp =  saturateInt32 (*ap  % (double) *bp);
1354                                        ap++;
1355                                        bp++;
1356                                        cp++;
1357                                    }
1358                                }
1359                            } else {
1360                                // dim = 1
1361                                ap = (Int32*)range.Item2;
1362                                bp = (Int32*)range.Item3;
1363                                cp = (Int32*)range.Item4;
1364                                for (int s = 0; s < range.Item1; s++) {
1365                                   Int32 val = *bp++;
1366                                    int l = itLen;
1367                                    while (l > 10) {
1368                                        cp[0] =  saturateInt32 (ap[0]  % (double) val);
1369                                        cp[1] =  saturateInt32 (ap[1]  % (double) val);
1370                                        cp[2] =  saturateInt32 (ap[2]  % (double) val);
1371                                        cp[3] =  saturateInt32 (ap[3]  % (double) val);
1372                                        cp[4] =  saturateInt32 (ap[4]  % (double) val);
1373                                        cp[5] =  saturateInt32 (ap[5]  % (double) val);
1374                                        cp[6] =  saturateInt32 (ap[6]  % (double) val);
1375                                        cp[7] =  saturateInt32 (ap[7]  % (double) val);
1376                                        cp[8] =  saturateInt32 (ap[8]  % (double) val);
1377                                        cp[9] =  saturateInt32 (ap[9]  % (double) val);
1378                                        cp[10] =  saturateInt32 (ap[10]  % (double) val);
1379                                        ap += 11;
1380                                        cp += 11;
1381                                        l -= 11;
1382                                    }
1383                                    while (l-- > 0) {
1384                                        *cp =  saturateInt32 (*ap  % (double) val);
1385                                        ap++;
1386                                        cp++;
1387                                    }
1388                                }
1389                            }
1390                            break;
1391                        case BinOptItExMode.AVI:
1392                            if (dim == 0) {
1393                                cp = (Int32*)range.Item4;
1394                                for (int s = 0; s < range.Item1; s++) {
1395                                    bp = (Int32*)range.Item3;
1396                                    int l = itLen;
1397                                    while (l > 10) {
1398                                        cp[0] =  saturateInt32 (cp[0]  % (double) bp[0]);
1399                                        cp[1] =  saturateInt32 (cp[1]  % (double) bp[1]);
1400                                        cp[2] =  saturateInt32 (cp[2]  % (double) bp[2]);
1401                                        cp[3] =  saturateInt32 (cp[3]  % (double) bp[3]);
1402                                        cp[4] =  saturateInt32 (cp[4]  % (double) bp[4]);
1403                                        cp[5] =  saturateInt32 (cp[5]  % (double) bp[5]);
1404                                        cp[6] =  saturateInt32 (cp[6]  % (double) bp[6]);
1405                                        cp[7] =  saturateInt32 (cp[7]  % (double) bp[7]);
1406                                        cp[8] =  saturateInt32 (cp[8]  % (double) bp[8]);
1407                                        cp[9] =  saturateInt32 (cp[9]  % (double) bp[9]);
1408                                        cp[10] =  saturateInt32 (cp[10]  % (double) bp[10]);
1409                                        bp += 11;
1410                                        cp += 11;
1411                                        l -= 11;
1412                                    }
1413                                    while (l-- > 0) {
1414                                        *cp =  saturateInt32 (*cp  % (double) *bp);
1415                                        bp++;
1416                                        cp++;
1417                                    }
1418                                }
1419                            } else {
1420                                // dim = 1
1421                                bp = (Int32*)range.Item3;
1422                                cp = (Int32*)range.Item4;
1423                                for (int s = 0; s < range.Item1; s++) {
1424                                   
1425                                    Int32 val = *bp++;
1426                                    int l = itLen;
1427                                    while (l > 10) {
1428                                        cp[0] =  saturateInt32 (cp[0]  % (double) val);
1429                                        cp[1] =  saturateInt32 (cp[1]  % (double) val);
1430                                        cp[2] =  saturateInt32 (cp[2]  % (double) val);
1431                                        cp[3] =  saturateInt32 (cp[3]  % (double) val);
1432                                        cp[4] =  saturateInt32 (cp[4]  % (double) val);
1433                                        cp[5] =  saturateInt32 (cp[5]  % (double) val);
1434                                        cp[6] =  saturateInt32 (cp[6]  % (double) val);
1435                                        cp[7] =  saturateInt32 (cp[7]  % (double) val);
1436                                        cp[8] =  saturateInt32 (cp[8]  % (double) val);
1437                                        cp[9] =  saturateInt32 (cp[9]  % (double) val);
1438                                        cp[10] =  saturateInt32 (cp[10]  % (double) val);
1439                                        cp += 11;
1440                                        l -= 11;
1441                                    }
1442                                    while (l --> 0) {
1443                                        *cp =  saturateInt32 (*cp  % (double) val);
1444                                        cp++;
1445                                    }
1446                                }
1447                            }
1448                            break;
1449                    }
1450                    System.Threading.Interlocked.Decrement(ref workerCount);
1451                };
1452                #endregion
1453
1454                #region work distribution
1455                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
1456                if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count
1457                    && outDims[1] > 1) {
1458                        if (outDims[1] > workItemCount) {
1459                        workItemLength = outDims[1] / workItemCount;
1460                    } else {
1461                        workItemLength = outDims[1] / 2;
1462                        workItemCount = 2;
1463                    }
1464                } else {
1465                    workItemLength = outDims[1];
1466                    workItemCount = 1;
1467                }
1468
1469                fixed ( Int32* arrAP = arrA)
1470                fixed ( Int32* arrBP = arrB)
1471                fixed ( Int32* retArrP = retArr) {
1472
1473                    for (; i < workItemCount - 1; i++) {
1474                        Tuple<int, IntPtr, IntPtr, IntPtr> range = new Tuple<int, IntPtr, IntPtr, IntPtr>
1475                               (workItemLength
1476                               , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
1477                               , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
1478                               , (IntPtr)(retArrP + i * outDims[0] * workItemLength));
1479                        System.Threading.Interlocked.Increment(ref workerCount);
1480                        ILThreadPool.QueueUserWorkItem(i, worker, range);
1481                    }
1482                    // the last (or may the only) chunk is done right here
1483                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
1484                    worker(new Tuple<int, IntPtr, IntPtr, IntPtr>
1485                                (outDims[1] - i * workItemLength
1486                                , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
1487                                , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
1488                                , (IntPtr)(retArrP + i * outDims[0] * workItemLength)));
1489
1490                    ILThreadPool.Wait4Workers(ref workerCount);
1491                }
1492                #endregion
1493
1494                return new ILRetArray<Int32>(retStorage);
1495            //}  // no scopes here! it disables implace operations
1496        }
1497
1498        /// <summary>Modulus of array elements</summary>
1499        /// <param name="A">Input array A</param>
1500        /// <param name="B">Input array B</param>
1501        /// <returns>New array with result of elementwise modulus operation</returns>
1502        /// <remarks><para>On empty input an empty array will be returned.</para>
1503        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
1504        /// other array.</para>
1505        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
1506        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
1507        /// can be used to replace the (costly) repmat function for most binary operators.</para>
1508        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
1509        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
1510        public unsafe static ILRetArray<float>  mod(ILInArray<float> A, ILInArray<float> B) {
1511            using (ILScope.Enter(A,B)) {
1512                int outLen;
1513                BinOpItMode mode;
1514                float [] retArr;
1515                float [] arrA = A.GetArrayForRead();
1516                float[] arrB = B.GetArrayForRead();
1517                ILSize outDims;
1518                #region determine operation mode
1519                if (A.IsScalar) {
1520                    outDims = B.Size;
1521                    if (B.IsScalar) {
1522                       
1523                        return new  ILRetArray<float> (new  float [1]{  (A.GetValue(0)  % B.GetValue(0))}, A.Size);
1524                    } else if (B.IsEmpty) {
1525                        return  ILRetArray<float>.empty(outDims);
1526                    } else {
1527                        outLen = outDims.NumberOfElements;
1528                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
1529                            retArr = ILMemoryPool.Pool.New< float > (outLen);
1530                            mode = BinOpItMode.SAN;
1531                        } else {
1532                            mode = BinOpItMode.SAI;
1533                        }
1534                    }
1535                } else {
1536                    outDims = A.Size;
1537                    if (B.IsScalar) {
1538                        if (A.IsEmpty) {
1539                            return  ILRetArray<float>.empty(A.Size); 
1540                        }
1541                        outLen = A.S.NumberOfElements;
1542                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
1543                            retArr = ILMemoryPool.Pool.New< float > (outLen);
1544                            mode = BinOpItMode.ASN;
1545                        } else {
1546                            mode = BinOpItMode.ASI;
1547                        }
1548                    } else {
1549                        // array + array
1550                        if (!A.Size.IsSameSize(B.Size)) {
1551                            return  modEx(A,B);
1552                        }
1553                        outLen = A.S.NumberOfElements;
1554                        if (A.TryGetStorage4InplaceOp(out retArr))
1555                            mode  = BinOpItMode.AAIA;
1556                        else if (B.TryGetStorage4InplaceOp(out retArr))
1557                            mode = BinOpItMode.AAIB;
1558                        else {
1559                            retArr = ILMemoryPool.Pool.New< float > (outLen);
1560                            mode = BinOpItMode.AAN;
1561                        }
1562                    }
1563                }
1564                #endregion
1565                ILDenseStorage<float> retStorage = new ILDenseStorage<float>(retArr, outDims);
1566                int i = 0, workerCount = 1;
1567                Action<object> worker = data => {
1568                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
1569                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
1570                    float* cp = (float*)range.Item5 + range.Item1;
1571                    float scalar;
1572                    int j = range.Item2;
1573                    #region loops
1574                    switch (mode) {
1575                        case BinOpItMode.AAIA:
1576                           float* bp = ((float*)range.Item4 + range.Item1);
1577                            while (j > 20) {
1578                                cp[0] =   (cp[0]  % bp[0]);
1579                                cp[1] =   (cp[1]  % bp[1]);
1580                                cp[2] =   (cp[2]  % bp[2]);
1581                                cp[3] =   (cp[3]  % bp[3]);
1582                                cp[4] =   (cp[4]  % bp[4]);
1583                                cp[5] =   (cp[5]  % bp[5]);
1584                                cp[6] =   (cp[6]  % bp[6]);
1585                                cp[7] =   (cp[7]  % bp[7]);
1586                                cp[8] =   (cp[8]  % bp[8]);
1587                                cp[9] =   (cp[9]  % bp[9]);
1588                                cp[10] =   (cp[10]  % bp[10]);
1589                                cp[11] =   (cp[11]  % bp[11]);
1590                                cp[12] =   (cp[12]  % bp[12]);
1591                                cp[13] =   (cp[13]  % bp[13]);
1592                                cp[14] =   (cp[14]  % bp[14]);
1593                                cp[15] =   (cp[15]  % bp[15]);
1594                                cp[16] =   (cp[16]  % bp[16]);
1595                                cp[17] =   (cp[17]  % bp[17]);
1596                                cp[18] =   (cp[18]  % bp[18]);
1597                                cp[19] =   (cp[19]  % bp[19]);
1598                                cp[20] =   (cp[20]  % bp[20]);
1599                                cp += 21; bp += 21; j -= 21;
1600                            }
1601                            while (j --> 0) {
1602                               
1603                                *cp =   (*cp  % *bp);
1604                                cp++; bp++;
1605                            }
1606                            break;
1607                        case BinOpItMode.AAIB:
1608                           float* ap = ((float*)range.Item3 + range.Item1);
1609                            while (j > 20) {
1610                               
1611                                cp[0] =   (ap[0]  % cp[0]);
1612                                cp[1] =   (ap[1]  % cp[1]);
1613                                cp[2] =   (ap[2]  % cp[2]);
1614                                cp[3] =   (ap[3]  % cp[3]);
1615                                cp[4] =   (ap[4]  % cp[4]);
1616                                cp[5] =   (ap[5]  % cp[5]);
1617                                cp[6] =   (ap[6]  % cp[6]);
1618                                cp[7] =   (ap[7]  % cp[7]);
1619                                cp[8] =   (ap[8]  % cp[8]);
1620                                cp[9] =   (ap[9]  % cp[9]);
1621                                cp[10] =   (ap[10]  % cp[10]);
1622                                cp[11] =   (ap[11]  % cp[11]);
1623                                cp[12] =   (ap[12]  % cp[12]);
1624                                cp[13] =   (ap[13]  % cp[13]);
1625                                cp[14] =   (ap[14]  % cp[14]);
1626                                cp[15] =   (ap[15]  % cp[15]);
1627                                cp[16] =   (ap[16]  % cp[16]);
1628                                cp[17] =   (ap[17]  % cp[17]);
1629                                cp[18] =   (ap[18]  % cp[18]);
1630                                cp[19] =   (ap[19]  % cp[19]);
1631                                cp[20] =   (ap[20]  % cp[20]);
1632                                ap += 21; cp += 21; j -= 21;
1633                            }
1634                            while (j --> 0) {
1635                               
1636                                *cp =   (*ap  % *cp);
1637                                ap++; cp++;
1638                            }
1639                            break;
1640                        case BinOpItMode.AAN:
1641                            ap = ((float*)range.Item3 + range.Item1);
1642                            bp = ((float*)range.Item4 + range.Item1);
1643                            while (j > 20) {
1644                               
1645                                cp[0] =   (ap[0]  % bp[0]);
1646                                cp[1] =   (ap[1]  % bp[1]);
1647                                cp[2] =   (ap[2]  % bp[2]);
1648                                cp[3] =   (ap[3]  % bp[3]);
1649                                cp[4] =   (ap[4]  % bp[4]);
1650                                cp[5] =   (ap[5]  % bp[5]);
1651                                cp[6] =   (ap[6]  % bp[6]);
1652                                cp[7] =   (ap[7]  % bp[7]);
1653                                cp[8] =   (ap[8]  % bp[8]);
1654                                cp[9] =   (ap[9]  % bp[9]);
1655                                cp[10] =   (ap[10]  % bp[10]);
1656                                cp[11] =   (ap[11]  % bp[11]);
1657                                cp[12] =   (ap[12]  % bp[12]);
1658                                cp[13] =   (ap[13]  % bp[13]);
1659                                cp[14] =   (ap[14]  % bp[14]);
1660                                cp[15] =   (ap[15]  % bp[15]);
1661                                cp[16] =   (ap[16]  % bp[16]);
1662                                cp[17] =   (ap[17]  % bp[17]);
1663                                cp[18] =   (ap[18]  % bp[18]);
1664                                cp[19] =   (ap[19]  % bp[19]);
1665                                cp[20] =   (ap[20]  % bp[20]);
1666                                ap+=21; bp+=21; cp+=21; j-=21;
1667                            }
1668                            while (j --> 0) {
1669                               
1670                                *cp =   (*ap  % *bp);
1671                                ap++; bp++; cp++;
1672                            }
1673                            break;
1674                        case BinOpItMode.ASI:
1675                            scalar = *((float*)range.Item4);
1676                            while (j > 20) {
1677                               
1678                                cp[0] =   (cp[0]  % scalar);
1679                                cp[1] =   (cp[1]  % scalar);
1680                                cp[2] =   (cp[2]  % scalar);
1681                                cp[3] =   (cp[3]  % scalar);
1682                                cp[4] =   (cp[4]  % scalar);
1683                                cp[5] =   (cp[5]  % scalar);
1684                                cp[6] =   (cp[6]  % scalar);
1685                                cp[7] =   (cp[7]  % scalar);
1686                                cp[8] =   (cp[8]  % scalar);
1687                                cp[9] =   (cp[9]  % scalar);
1688                                cp[10] =   (cp[10]  % scalar);
1689                                cp[11] =   (cp[11]  % scalar);
1690                                cp[12] =   (cp[12]  % scalar);
1691                                cp[13] =   (cp[13]  % scalar);
1692                                cp[14] =   (cp[14]  % scalar);
1693                                cp[15] =   (cp[15]  % scalar);
1694                                cp[16] =   (cp[16]  % scalar);
1695                                cp[17] =   (cp[17]  % scalar);
1696                                cp[18] =   (cp[18]  % scalar);
1697                                cp[19] =   (cp[19]  % scalar);
1698                                cp[20] =   (cp[20]  % scalar);
1699                                cp += 21; j -= 21;
1700                            }
1701                            while (j --> 0) {
1702                               
1703                                *cp =   (*cp  % scalar);
1704                                cp++;
1705                            }
1706                            break;
1707                        case BinOpItMode.ASN:
1708                            ap = ((float*)range.Item3 + range.Item1);
1709                            scalar = *((float*)range.Item4);
1710                            while (j > 20) {
1711                               
1712                                cp[0] =   (ap[0]  % scalar);
1713                                cp[1] =   (ap[1]  % scalar);
1714                                cp[2] =   (ap[2]  % scalar);
1715                                cp[3] =   (ap[3]  % scalar);
1716                                cp[4] =   (ap[4]  % scalar);
1717                                cp[5] =   (ap[5]  % scalar);
1718                                cp[6] =   (ap[6]  % scalar);
1719                                cp[7] =   (ap[7]  % scalar);
1720                                cp[8] =   (ap[8]  % scalar);
1721                                cp[9] =   (ap[9]  % scalar);
1722                                cp[10] =   (ap[10]  % scalar);
1723                                cp[11] =   (ap[11]  % scalar);
1724                                cp[12] =   (ap[12]  % scalar);
1725                                cp[13] =   (ap[13]  % scalar);
1726                                cp[14] =   (ap[14]  % scalar);
1727                                cp[15] =   (ap[15]  % scalar);
1728                                cp[16] =   (ap[16]  % scalar);
1729                                cp[17] =   (ap[17]  % scalar);
1730                                cp[18] =   (ap[18]  % scalar);
1731                                cp[19] =   (ap[19]  % scalar);
1732                                cp[20] =   (ap[20]  % scalar);
1733                                ap+=21; cp+=21; j -= 21;
1734                            }
1735                            while (j --> 0) {
1736                               
1737                                *cp =   (*ap  % scalar);
1738                                ap++; cp++;
1739                            }
1740                            break;
1741                        case BinOpItMode.SAI:
1742                            scalar = *((float*)range.Item3);
1743                            while (j > 20) {
1744                               
1745                                cp[0] =   (scalar  % cp[0]);
1746                                cp[1] =   (scalar  % cp[1]);
1747                                cp[2] =   (scalar  % cp[2]);
1748                                cp[3] =   (scalar  % cp[3]);
1749                                cp[4] =   (scalar  % cp[4]);
1750                                cp[5] =   (scalar  % cp[5]);
1751                                cp[6] =   (scalar  % cp[6]);
1752                                cp[7] =   (scalar  % cp[7]);
1753                                cp[8] =   (scalar  % cp[8]);
1754                                cp[9] =   (scalar  % cp[9]);
1755                                cp[10] =   (scalar  % cp[10]);
1756                                cp[11] =   (scalar  % cp[11]);
1757                                cp[12] =   (scalar  % cp[12]);
1758                                cp[13] =   (scalar  % cp[13]);
1759                                cp[14] =   (scalar  % cp[14]);
1760                                cp[15] =   (scalar  % cp[15]);
1761                                cp[16] =   (scalar  % cp[16]);
1762                                cp[17] =   (scalar  % cp[17]);
1763                                cp[18] =   (scalar  % cp[18]);
1764                                cp[19] =   (scalar  % cp[19]);
1765                                cp[20] =   (scalar  % cp[20]);
1766                                cp += 21; j -= 21;
1767                            }
1768                            while (j --> 0) {
1769                               
1770                                *cp =   (scalar  % *cp);
1771                                cp++;
1772                            }
1773                            break;
1774                        case BinOpItMode.SAN:
1775                            scalar = *((float*)range.Item3);
1776                            bp = ((float*)range.Item4 + range.Item1);
1777                            while (j > 20) {
1778                               
1779                                cp[0] =   (scalar  % bp[0]);
1780                                cp[1] =   (scalar  % bp[1]);
1781                                cp[2] =   (scalar  % bp[2]);
1782                                cp[3] =   (scalar  % bp[3]);
1783                                cp[4] =   (scalar  % bp[4]);
1784                                cp[5] =   (scalar  % bp[5]);
1785                                cp[6] =   (scalar  % bp[6]);
1786                                cp[7] =   (scalar  % bp[7]);
1787                                cp[8] =   (scalar  % bp[8]);
1788                                cp[9] =   (scalar  % bp[9]);
1789                                cp[10] =   (scalar  % bp[10]);
1790                                cp[11] =   (scalar  % bp[11]);
1791                                cp[12] =   (scalar  % bp[12]);
1792                                cp[13] =   (scalar  % bp[13]);
1793                                cp[14] =   (scalar  % bp[14]);
1794                                cp[15] =   (scalar  % bp[15]);
1795                                cp[16] =   (scalar  % bp[16]);
1796                                cp[17] =   (scalar  % bp[17]);
1797                                cp[18] =   (scalar  % bp[18]);
1798                                cp[19] =   (scalar  % bp[19]);
1799                                cp[20] =   (scalar  % bp[20]);
1800                                bp+=21; cp+=21; j -= 21;
1801                            }
1802                            while (j --> 0) {
1803                               
1804                                *cp =   (scalar  % *bp);
1805                                bp++; cp++;
1806                            }
1807                            break;
1808                        default:
1809                            break;
1810                    }
1811                    #endregion
1812                    System.Threading.Interlocked.Decrement(ref workerCount);
1813                    //retStorage.PendingEvents.Signal();
1814                };
1815
1816                #region do the work
1817                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
1818                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
1819                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
1820                        workItemLength = outLen / workItemCount;
1821                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
1822                    } else {
1823                        workItemLength = outLen / 2;
1824                        workItemCount = 2;
1825                    }
1826                } else {
1827                    workItemLength = outLen;
1828                    workItemCount = 1;
1829                }
1830               
1831                fixed ( float* arrAP = arrA)
1832                fixed ( float* arrBP = arrB)
1833                fixed ( float* retArrP = retArr) {
1834
1835                    for (; i < workItemCount - 1; i++) {
1836                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
1837                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
1838                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
1839                        System.Threading.Interlocked.Increment(ref workerCount);
1840                        ILThreadPool.QueueUserWorkItem(i, worker, range);
1841                    }
1842                    // the last (or may the only) chunk is done right here
1843                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
1844                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
1845                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
1846
1847                    ILThreadPool.Wait4Workers(ref workerCount);
1848                }
1849
1850                #endregion
1851                return new  ILRetArray< float>(retStorage);
1852            }
1853        }
1854
1855        private static unsafe ILRetArray<float>  modEx(ILInArray<float> A, ILInArray<float> B) {
1856            //using (ILScope.Enter(A, B)) { we cannot start a new scope here, since this would prevent A and B to be used implace if applicable
1857
1858                #region parameter checking
1859                if (isnull(A) || isnull(B))
1860                    return empty<float>(ILSize.Empty00);
1861                if (A.IsEmpty) {
1862                    return empty<float>(B.S);
1863                } else if (B.IsEmpty) {
1864                    return empty<float>(A.S);
1865                }
1866                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
1867                //    return add(A,B);
1868                int dim = -1;
1869                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
1870                    if (A.S[l] != B.S[l]) {
1871                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
1872                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
1873                        }
1874                        dim = l;
1875                    }
1876                }
1877                if (dim > 1)
1878                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
1879                dim = -(dim - 1);  // 0 -> 1, 1 -> 0
1880                #endregion
1881
1882                #region parameter preparation
1883               
1884                float[] retArr;
1885               
1886                float[] arrA = A.GetArrayForRead();
1887               
1888                float[] arrB = B.GetArrayForRead();
1889                ILSize outDims;
1890                BinOptItExMode mode;
1891                int workItemMultiplierLenA;
1892                int workItemMultiplierLenB;
1893                if (A.IsVector) {
1894                    outDims = B.S;
1895                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
1896                        retArr = ILMemoryPool.Pool.New<float>(outDims.NumberOfElements);
1897                        mode = BinOptItExMode.VAN;
1898                    } else {
1899                        mode = BinOptItExMode.VAI;
1900                    }
1901                    workItemMultiplierLenB = outDims[0];
1902                    workItemMultiplierLenA = dim;  // 0 for column, 1 for row vector
1903                } else if (B.IsVector) {
1904                    outDims = A.S;
1905                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
1906                        retArr = ILMemoryPool.Pool.New<float>(outDims.NumberOfElements);
1907                        mode = BinOptItExMode.AVN;
1908                    } else {
1909                        mode = BinOptItExMode.AVI;
1910                    }
1911                    workItemMultiplierLenB = dim;  // 0 for column, 1 for row vector
1912                    workItemMultiplierLenA = outDims[0];
1913                } else {
1914                    throw new ILArgumentException("A and B must have the same size except for one singleton dimension in either A or B");
1915                }
1916                int itLen = outDims[0]; // (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
1917                #endregion
1918
1919                #region worker loops definition
1920                ILDenseStorage<float> retStorage = new ILDenseStorage<float>(retArr, outDims);
1921                int workerCount = 1;
1922                Action<object> worker = data => {
1923                    // expects: iStart, iLen, ap, bp, cp
1924                    Tuple<int, IntPtr, IntPtr, IntPtr> range =
1925                        (Tuple<int, IntPtr, IntPtr, IntPtr>)data;
1926                   
1927                    float* ap;
1928                   
1929                    float* bp;
1930                   
1931                    float* cp;
1932                    switch (mode) {
1933                        case BinOptItExMode.VAN:
1934                            if (dim == 0) {
1935                                bp = (float*)range.Item3;
1936                                cp = (float*)range.Item4;
1937                                for (int s = 0; s < range.Item1; s++) {
1938                                    ap = (float*)range.Item2;
1939                                    int l = itLen;
1940                                    while (l > 10) {
1941                                        cp[0] =   (ap[0]  % bp[0]);
1942                                        cp[1] =   (ap[1]  % bp[1]);
1943                                        cp[2] =   (ap[2]  % bp[2]);
1944                                        cp[3] =   (ap[3]  % bp[3]);
1945                                        cp[4] =   (ap[4]  % bp[4]);
1946                                        cp[5] =   (ap[5]  % bp[5]);
1947                                        cp[6] =   (ap[6]  % bp[6]);
1948                                        cp[7] =   (ap[7]  % bp[7]);
1949                                        cp[8] =   (ap[8]  % bp[8]);
1950                                        cp[9] =   (ap[9]  % bp[9]);
1951                                        cp[10] =   (ap[10]  % bp[10]);
1952                                        ap += 11;
1953                                        bp += 11;
1954                                        cp += 11;
1955                                        l -= 11;
1956                                    }
1957                                    while (l-- > 0) {
1958                                        *cp++ =   (*ap++  % *bp++);
1959                                    }
1960                                }
1961                            } else {
1962                                // dim == 1
1963                                ap = (float*)range.Item2;
1964                                bp = (float*)range.Item3;
1965                                cp = (float*)range.Item4;
1966                                for (int s = 0; s < range.Item1; s++) {
1967                                   float val = *ap++;
1968                                    int l = itLen;
1969                                    while (l > 10) {
1970                                        cp[0] =   (val  % bp[0]);
1971                                        cp[1] =   (val  % bp[1]);
1972                                        cp[2] =   (val  % bp[2]);
1973                                        cp[3] =   (val  % bp[3]);
1974                                        cp[4] =   (val  % bp[4]);
1975                                        cp[5] =   (val  % bp[5]);
1976                                        cp[6] =   (val  % bp[6]);
1977                                        cp[7] =   (val  % bp[7]);
1978                                        cp[8] =   (val  % bp[8]);
1979                                        cp[9] =   (val  % bp[9]);
1980                                        cp[10] =   (val  % bp[10]);
1981                                        bp += 11;
1982                                        cp += 11;
1983                                        l -= 11;
1984                                    }
1985                                    while (l-- > 0) {
1986                                        *cp++ =   (val  % *bp++);
1987                                    }
1988                                }
1989                            }
1990                            break;
1991                        case BinOptItExMode.VAI:
1992                            if (dim == 0) {
1993                                cp = (float*)range.Item4;
1994                                for (int s = 0; s < range.Item1; s++) {
1995                                    ap = (float*)range.Item2;
1996                                    int l = itLen;
1997                                    while (l > 10) {
1998                                        cp[0] =   (ap[0]  % cp[0]);
1999                                        cp[1] =   (ap[1]  % cp[1]);
2000                                        cp[2] =   (ap[2]  % cp[2]);
2001                                        cp[3] =   (ap[3]  % cp[3]);
2002                                        cp[4] =   (ap[4]  % cp[4]);
2003                                        cp[5] =   (ap[5]  % cp[5]);
2004                                        cp[6] =   (ap[6]  % cp[6]);
2005                                        cp[7] =   (ap[7]  % cp[7]);
2006                                        cp[8] =   (ap[8]  % cp[8]);
2007                                        cp[9] =   (ap[9]  % cp[9]);
2008                                        cp[10] =   (ap[10]  % cp[10]);
2009                                        ap += 11;
2010                                        cp += 11;
2011                                        l -= 11;
2012                                    }
2013                                    while (l-- > 0) {
2014                                        *cp =   (*ap++  % *cp);
2015                                        cp++;
2016                                    }
2017                                }
2018                            } else {
2019                                // dim == 1
2020                                cp = (float*)range.Item4;
2021                                ap = (float*)range.Item2;
2022                                for (int s = 0; s < range.Item1; s++) {
2023                                   
2024                                    float val = *ap++;
2025                                    int l = itLen;
2026                                    while (l > 10) {
2027                                        cp[0] =   (val  % cp[0]);
2028                                        cp[1] =   (val  % cp[1]);
2029                                        cp[2] =   (val  % cp[2]);
2030                                        cp[3] =   (val  % cp[3]);
2031                                        cp[4] =   (val  % cp[4]);
2032                                        cp[5] =   (val  % cp[5]);
2033                                        cp[6] =   (val  % cp[6]);
2034                                        cp[7] =   (val  % cp[7]);
2035                                        cp[8] =   (val  % cp[8]);
2036                                        cp[9] =   (val  % cp[9]);
2037                                        cp[10] =   (val  % cp[10]);
2038                                        cp += 11;
2039                                        l -= 11;
2040                                    }
2041                                    while (l-- > 0) {
2042                                        *cp =   (val  % *cp);
2043                                        cp++;
2044                                    }
2045                                }
2046                            }
2047                            break;
2048                        case BinOptItExMode.AVN:
2049                            if (dim == 0) {
2050                                ap = (float*)range.Item2;
2051                                cp = (float*)range.Item4;
2052                                for (int s = 0; s < range.Item1; s++) {
2053                                    bp = (float*)range.Item3;
2054                                    int l = itLen;
2055                                    while (l > 10) {
2056                                        cp[0] =   (ap[0]  % bp[0]);
2057                                        cp[1] =   (ap[1]  % bp[1]);
2058                                        cp[2] =   (ap[2]  % bp[2]);
2059                                        cp[3] =   (ap[3]  % bp[3]);
2060                                        cp[4] =   (ap[4]  % bp[4]);
2061                                        cp[5] =   (ap[5]  % bp[5]);
2062                                        cp[6] =   (ap[6]  % bp[6]);
2063                                        cp[7] =   (ap[7]  % bp[7]);
2064                                        cp[8] =   (ap[8]  % bp[8]);
2065                                        cp[9] =   (ap[9]  % bp[9]);
2066                                        cp[10] =   (ap[10]  % bp[10]);
2067                                        ap += 11;
2068                                        bp += 11;
2069                                        cp += 11;
2070                                        l -= 11;
2071                                    }
2072                                    while (l-- > 0) {
2073                                        *cp =   (*ap  % *bp);
2074                                        ap++;
2075                                        bp++;
2076                                        cp++;
2077                                    }
2078                                }
2079                            } else {
2080                                // dim = 1
2081                                ap = (float*)range.Item2;
2082                                bp = (float*)range.Item3;
2083                                cp = (float*)range.Item4;
2084                                for (int s = 0; s < range.Item1; s++) {
2085                                   float val = *bp++;
2086                                    int l = itLen;
2087                                    while (l > 10) {
2088                                        cp[0] =   (ap[0]  % val);
2089                                        cp[1] =   (ap[1]  % val);
2090                                        cp[2] =   (ap[2]  % val);
2091                                        cp[3] =   (ap[3]  % val);
2092                                        cp[4] =   (ap[4]  % val);
2093                                        cp[5] =   (ap[5]  % val);
2094                                        cp[6] =   (ap[6]  % val);
2095                                        cp[7] =   (ap[7]  % val);
2096                                        cp[8] =   (ap[8]  % val);
2097                                        cp[9] =   (ap[9]  % val);
2098                                        cp[10] =   (ap[10]  % val);
2099                                        ap += 11;
2100                                        cp += 11;
2101                                        l -= 11;
2102                                    }
2103                                    while (l-- > 0) {
2104                                        *cp =   (*ap  % val);
2105                                        ap++;
2106                                        cp++;
2107                                    }
2108                                }
2109                            }
2110                            break;
2111                        case BinOptItExMode.AVI:
2112                            if (dim == 0) {
2113                                cp = (float*)range.Item4;
2114                                for (int s = 0; s < range.Item1; s++) {
2115                                    bp = (float*)range.Item3;
2116                                    int l = itLen;
2117                                    while (l > 10) {
2118                                        cp[0] =   (cp[0]  % bp[0]);
2119                                        cp[1] =   (cp[1]  % bp[1]);
2120                                        cp[2] =   (cp[2]  % bp[2]);
2121                                        cp[3] =   (cp[3]  % bp[3]);
2122                                        cp[4] =   (cp[4]  % bp[4]);
2123                                        cp[5] =   (cp[5]  % bp[5]);
2124                                        cp[6] =   (cp[6]  % bp[6]);
2125                                        cp[7] =   (cp[7]  % bp[7]);
2126                                        cp[8] =   (cp[8]  % bp[8]);
2127                                        cp[9] =   (cp[9]  % bp[9]);
2128                                        cp[10] =   (cp[10]  % bp[10]);
2129                                        bp += 11;
2130                                        cp += 11;
2131                                        l -= 11;
2132                                    }
2133                                    while (l-- > 0) {
2134                                        *cp =   (*cp  % *bp);
2135                                        bp++;
2136                                        cp++;
2137                                    }
2138                                }
2139                            } else {
2140                                // dim = 1
2141                                bp = (float*)range.Item3;
2142                                cp = (float*)range.Item4;
2143                                for (int s = 0; s < range.Item1; s++) {
2144                                   
2145                                    float val = *bp++;
2146                                    int l = itLen;
2147                                    while (l > 10) {
2148                                        cp[0] =   (cp[0]  % val);
2149                                        cp[1] =   (cp[1]  % val);
2150                                        cp[2] =   (cp[2]  % val);
2151                                        cp[3] =   (cp[3]  % val);
2152                                        cp[4] =   (cp[4]  % val);
2153                                        cp[5] =   (cp[5]  % val);
2154                                        cp[6] =   (cp[6]  % val);
2155                                        cp[7] =   (cp[7]  % val);
2156                                        cp[8] =   (cp[8]  % val);
2157                                        cp[9] =   (cp[9]  % val);
2158                                        cp[10] =   (cp[10]  % val);
2159                                        cp += 11;
2160                                        l -= 11;
2161                                    }
2162                                    while (l --> 0) {
2163                                        *cp =   (*cp  % val);
2164                                        cp++;
2165                                    }
2166                                }
2167                            }
2168                            break;
2169                    }
2170                    System.Threading.Interlocked.Decrement(ref workerCount);
2171                };
2172                #endregion
2173
2174                #region work distribution
2175                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
2176                if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count
2177                    && outDims[1] > 1) {
2178                        if (outDims[1] > workItemCount) {
2179                        workItemLength = outDims[1] / workItemCount;
2180                    } else {
2181                        workItemLength = outDims[1] / 2;
2182                        workItemCount = 2;
2183                    }
2184                } else {
2185                    workItemLength = outDims[1];
2186                    workItemCount = 1;
2187                }
2188
2189                fixed ( float* arrAP = arrA)
2190                fixed ( float* arrBP = arrB)
2191                fixed ( float* retArrP = retArr) {
2192
2193                    for (; i < workItemCount - 1; i++) {
2194                        Tuple<int, IntPtr, IntPtr, IntPtr> range = new Tuple<int, IntPtr, IntPtr, IntPtr>
2195                               (workItemLength
2196                               , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
2197                               , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
2198                               , (IntPtr)(retArrP + i * outDims[0] * workItemLength));
2199                        System.Threading.Interlocked.Increment(ref workerCount);
2200                        ILThreadPool.QueueUserWorkItem(i, worker, range);
2201                    }
2202                    // the last (or may the only) chunk is done right here
2203                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
2204                    worker(new Tuple<int, IntPtr, IntPtr, IntPtr>
2205                                (outDims[1] - i * workItemLength
2206                                , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
2207                                , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
2208                                , (IntPtr)(retArrP + i * outDims[0] * workItemLength)));
2209
2210                    ILThreadPool.Wait4Workers(ref workerCount);
2211                }
2212                #endregion
2213
2214                return new ILRetArray<float>(retStorage);
2215            //}  // no scopes here! it disables implace operations
2216        }
2217
2218        /// <summary>Modulus of array elements</summary>
2219        /// <param name="A">Input array A</param>
2220        /// <param name="B">Input array B</param>
2221        /// <returns>New array with result of elementwise modulus operation</returns>
2222        /// <remarks><para>On empty input an empty array will be returned.</para>
2223        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
2224        /// other array.</para>
2225        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
2226        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
2227        /// can be used to replace the (costly) repmat function for most binary operators.</para>
2228        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
2229        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
2230        public unsafe static ILRetArray<byte>  mod(ILInArray<byte> A, ILInArray<byte> B) {
2231            using (ILScope.Enter(A,B)) {
2232                int outLen;
2233                BinOpItMode mode;
2234                byte [] retArr;
2235                byte [] arrA = A.GetArrayForRead();
2236                byte[] arrB = B.GetArrayForRead();
2237                ILSize outDims;
2238                #region determine operation mode
2239                if (A.IsScalar) {
2240                    outDims = B.Size;
2241                    if (B.IsScalar) {
2242                       
2243                        return new  ILRetArray<byte> (new  byte [1]{ saturateByte (A.GetValue(0)  % (double) B.GetValue(0))}, A.Size);
2244                    } else if (B.IsEmpty) {
2245                        return  ILRetArray<byte>.empty(outDims);
2246                    } else {
2247                        outLen = outDims.NumberOfElements;
2248                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
2249                            retArr = ILMemoryPool.Pool.New< byte > (outLen);
2250                            mode = BinOpItMode.SAN;
2251                        } else {
2252                            mode = BinOpItMode.SAI;
2253                        }
2254                    }
2255                } else {
2256                    outDims = A.Size;
2257                    if (B.IsScalar) {
2258                        if (A.IsEmpty) {
2259                            return  ILRetArray<byte>.empty(A.Size); 
2260                        }
2261                        outLen = A.S.NumberOfElements;
2262                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
2263                            retArr = ILMemoryPool.Pool.New< byte > (outLen);
2264                            mode = BinOpItMode.ASN;
2265                        } else {
2266                            mode = BinOpItMode.ASI;
2267                        }
2268                    } else {
2269                        // array + array
2270                        if (!A.Size.IsSameSize(B.Size)) {
2271                            return  modEx(A,B);
2272                        }
2273                        outLen = A.S.NumberOfElements;
2274                        if (A.TryGetStorage4InplaceOp(out retArr))
2275                            mode  = BinOpItMode.AAIA;
2276                        else if (B.TryGetStorage4InplaceOp(out retArr))
2277                            mode = BinOpItMode.AAIB;
2278                        else {
2279                            retArr = ILMemoryPool.Pool.New< byte > (outLen);
2280                            mode = BinOpItMode.AAN;
2281                        }
2282                    }
2283                }
2284                #endregion
2285                ILDenseStorage<byte> retStorage = new ILDenseStorage<byte>(retArr, outDims);
2286                int i = 0, workerCount = 1;
2287                Action<object> worker = data => {
2288                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
2289                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
2290                    byte* cp = (byte*)range.Item5 + range.Item1;
2291                    byte scalar;
2292                    int j = range.Item2;
2293                    #region loops
2294                    switch (mode) {
2295                        case BinOpItMode.AAIA:
2296                           byte* bp = ((byte*)range.Item4 + range.Item1);
2297                            while (j > 20) {
2298                                cp[0] =  saturateByte (cp[0]  % (double) bp[0]);
2299                                cp[1] =  saturateByte (cp[1]  % (double) bp[1]);
2300                                cp[2] =  saturateByte (cp[2]  % (double) bp[2]);
2301                                cp[3] =  saturateByte (cp[3]  % (double) bp[3]);
2302                                cp[4] =  saturateByte (cp[4]  % (double) bp[4]);
2303                                cp[5] =  saturateByte (cp[5]  % (double) bp[5]);
2304                                cp[6] =  saturateByte (cp[6]  % (double) bp[6]);
2305                                cp[7] =  saturateByte (cp[7]  % (double) bp[7]);
2306                                cp[8] =  saturateByte (cp[8]  % (double) bp[8]);
2307                                cp[9] =  saturateByte (cp[9]  % (double) bp[9]);
2308                                cp[10] =  saturateByte (cp[10]  % (double) bp[10]);
2309                                cp[11] =  saturateByte (cp[11]  % (double) bp[11]);
2310                                cp[12] =  saturateByte (cp[12]  % (double) bp[12]);
2311                                cp[13] =  saturateByte (cp[13]  % (double) bp[13]);
2312                                cp[14] =  saturateByte (cp[14]  % (double) bp[14]);
2313                                cp[15] =  saturateByte (cp[15]  % (double) bp[15]);
2314                                cp[16] =  saturateByte (cp[16]  % (double) bp[16]);
2315                                cp[17] =  saturateByte (cp[17]  % (double) bp[17]);
2316                                cp[18] =  saturateByte (cp[18]  % (double) bp[18]);
2317                                cp[19] =  saturateByte (cp[19]  % (double) bp[19]);
2318                                cp[20] =  saturateByte (cp[20]  % (double) bp[20]);
2319                                cp += 21; bp += 21; j -= 21;
2320                            }
2321                            while (j --> 0) {
2322                               
2323                                *cp =  saturateByte (*cp  % (double) *bp);
2324                                cp++; bp++;
2325                            }
2326                            break;
2327                        case BinOpItMode.AAIB:
2328                           byte* ap = ((byte*)range.Item3 + range.Item1);
2329                            while (j > 20) {
2330                               
2331                                cp[0] =  saturateByte (ap[0]  % (double) cp[0]);
2332                                cp[1] =  saturateByte (ap[1]  % (double) cp[1]);
2333                                cp[2] =  saturateByte (ap[2]  % (double) cp[2]);
2334                                cp[3] =  saturateByte (ap[3]  % (double) cp[3]);
2335                                cp[4] =  saturateByte (ap[4]  % (double) cp[4]);
2336                                cp[5] =  saturateByte (ap[5]  % (double) cp[5]);
2337                                cp[6] =  saturateByte (ap[6]  % (double) cp[6]);
2338                                cp[7] =  saturateByte (ap[7]  % (double) cp[7]);
2339                                cp[8] =  saturateByte (ap[8]  % (double) cp[8]);
2340                                cp[9] =  saturateByte (ap[9]  % (double) cp[9]);
2341                                cp[10] =  saturateByte (ap[10]  % (double) cp[10]);
2342                                cp[11] =  saturateByte (ap[11]  % (double) cp[11]);
2343                                cp[12] =  saturateByte (ap[12]  % (double) cp[12]);
2344                                cp[13] =  saturateByte (ap[13]  % (double) cp[13]);
2345                                cp[14] =  saturateByte (ap[14]  % (double) cp[14]);
2346                                cp[15] =  saturateByte (ap[15]  % (double) cp[15]);
2347                                cp[16] =  saturateByte (ap[16]  % (double) cp[16]);
2348                                cp[17] =  saturateByte (ap[17]  % (double) cp[17]);
2349                                cp[18] =  saturateByte (ap[18]  % (double) cp[18]);
2350                                cp[19] =  saturateByte (ap[19]  % (double) cp[19]);
2351                                cp[20] =  saturateByte (ap[20]  % (double) cp[20]);
2352                                ap += 21; cp += 21; j -= 21;
2353                            }
2354                            while (j --> 0) {
2355                               
2356                                *cp =  saturateByte (*ap  % (double) *cp);
2357                                ap++; cp++;
2358                            }
2359                            break;
2360                        case BinOpItMode.AAN:
2361                            ap = ((byte*)range.Item3 + range.Item1);
2362                            bp = ((byte*)range.Item4 + range.Item1);
2363                            while (j > 20) {
2364                               
2365                                cp[0] =  saturateByte (ap[0]  % (double) bp[0]);
2366                                cp[1] =  saturateByte (ap[1]  % (double) bp[1]);
2367                                cp[2] =  saturateByte (ap[2]  % (double) bp[2]);
2368                                cp[3] =  saturateByte (ap[3]  % (double) bp[3]);
2369                                cp[4] =  saturateByte (ap[4]  % (double) bp[4]);
2370                                cp[5] =  saturateByte (ap[5]  % (double) bp[5]);
2371                                cp[6] =  saturateByte (ap[6]  % (double) bp[6]);
2372                                cp[7] =  saturateByte (ap[7]  % (double) bp[7]);
2373                                cp[8] =  saturateByte (ap[8]  % (double) bp[8]);
2374                                cp[9] =  saturateByte (ap[9]  % (double) bp[9]);
2375                                cp[10] =  saturateByte (ap[10]  % (double) bp[10]);
2376                                cp[11] =  saturateByte (ap[11]  % (double) bp[11]);
2377                                cp[12] =  saturateByte (ap[12]  % (double) bp[12]);
2378                                cp[13] =  saturateByte (ap[13]  % (double) bp[13]);
2379                                cp[14] =  saturateByte (ap[14]  % (double) bp[14]);
2380                                cp[15] =  saturateByte (ap[15]  % (double) bp[15]);
2381                                cp[16] =  saturateByte (ap[16]  % (double) bp[16]);
2382                                cp[17] =  saturateByte (ap[17]  % (double) bp[17]);
2383                                cp[18] =  saturateByte (ap[18]  % (double) bp[18]);
2384                                cp[19] =  saturateByte (ap[19]  % (double) bp[19]);
2385                                cp[20] =  saturateByte (ap[20]  % (double) bp[20]);
2386                                ap+=21; bp+=21; cp+=21; j-=21;
2387                            }
2388                            while (j --> 0) {
2389                               
2390                                *cp =  saturateByte (*ap  % (double) *bp);
2391                                ap++; bp++; cp++;
2392                            }
2393                            break;
2394                        case BinOpItMode.ASI:
2395                            scalar = *((byte*)range.Item4);
2396                            while (j > 20) {
2397                               
2398                                cp[0] =  saturateByte (cp[0]  % (double) scalar);
2399                                cp[1] =  saturateByte (cp[1]  % (double) scalar);
2400                                cp[2] =  saturateByte (cp[2]  % (double) scalar);
2401                                cp[3] =  saturateByte (cp[3]  % (double) scalar);
2402                                cp[4] =  saturateByte (cp[4]  % (double) scalar);
2403                                cp[5] =  saturateByte (cp[5]  % (double) scalar);
2404                                cp[6] =  saturateByte (cp[6]  % (double) scalar);
2405                                cp[7] =  saturateByte (cp[7]  % (double) scalar);
2406                                cp[8] =  saturateByte (cp[8]  % (double) scalar);
2407                                cp[9] =  saturateByte (cp[9]  % (double) scalar);
2408                                cp[10] =  saturateByte (cp[10]  % (double) scalar);
2409                                cp[11] =  saturateByte (cp[11]  % (double) scalar);
2410                                cp[12] =  saturateByte (cp[12]  % (double) scalar);
2411                                cp[13] =  saturateByte (cp[13]  % (double) scalar);
2412                                cp[14] =  saturateByte (cp[14]  % (double) scalar);
2413                                cp[15] =  saturateByte (cp[15]  % (double) scalar);
2414                                cp[16] =  saturateByte (cp[16]  % (double) scalar);
2415                                cp[17] =  saturateByte (cp[17]  % (double) scalar);
2416                                cp[18] =  saturateByte (cp[18]  % (double) scalar);
2417                                cp[19] =  saturateByte (cp[19]  % (double) scalar);
2418                                cp[20] =  saturateByte (cp[20]  % (double) scalar);
2419                                cp += 21; j -= 21;
2420                            }
2421                            while (j --> 0) {
2422                               
2423                                *cp =  saturateByte (*cp  % (double) scalar);
2424                                cp++;
2425                            }
2426                            break;
2427                        case BinOpItMode.ASN:
2428                            ap = ((byte*)range.Item3 + range.Item1);
2429                            scalar = *((byte*)range.Item4);
2430                            while (j > 20) {
2431                               
2432                                cp[0] =  saturateByte (ap[0]  % (double) scalar);
2433                                cp[1] =  saturateByte (ap[1]  % (double) scalar);
2434                                cp[2] =  saturateByte (ap[2]  % (double) scalar);
2435                                cp[3] =  saturateByte (ap[3]  % (double) scalar);
2436                                cp[4] =  saturateByte (ap[4]  % (double) scalar);
2437                                cp[5] =  saturateByte (ap[5]  % (double) scalar);
2438                                cp[6] =  saturateByte (ap[6]  % (double) scalar);
2439                                cp[7] =  saturateByte (ap[7]  % (double) scalar);
2440                                cp[8] =  saturateByte (ap[8]  % (double) scalar);
2441                                cp[9] =  saturateByte (ap[9]  % (double) scalar);
2442                                cp[10] =  saturateByte (ap[10]  % (double) scalar);
2443                                cp[11] =  saturateByte (ap[11]  % (double) scalar);
2444                                cp[12] =  saturateByte (ap[12]  % (double) scalar);
2445                                cp[13] =  saturateByte (ap[13]  % (double) scalar);
2446                                cp[14] =  saturateByte (ap[14]  % (double) scalar);
2447                                cp[15] =  saturateByte (ap[15]  % (double) scalar);
2448                                cp[16] =  saturateByte (ap[16]  % (double) scalar);
2449                                cp[17] =  saturateByte (ap[17]  % (double) scalar);
2450                                cp[18] =  saturateByte (ap[18]  % (double) scalar);
2451                                cp[19] =  saturateByte (ap[19]  % (double) scalar);
2452                                cp[20] =  saturateByte (ap[20]  % (double) scalar);
2453                                ap+=21; cp+=21; j -= 21;
2454                            }
2455                            while (j --> 0) {
2456                               
2457                                *cp =  saturateByte (*ap  % (double) scalar);
2458                                ap++; cp++;
2459                            }
2460                            break;
2461                        case BinOpItMode.SAI:
2462                            scalar = *((byte*)range.Item3);
2463                            while (j > 20) {
2464                               
2465                                cp[0] =  saturateByte (scalar  % (double) cp[0]);
2466                                cp[1] =  saturateByte (scalar  % (double) cp[1]);
2467                                cp[2] =  saturateByte (scalar  % (double) cp[2]);
2468                                cp[3] =  saturateByte (scalar  % (double) cp[3]);
2469                                cp[4] =  saturateByte (scalar  % (double) cp[4]);
2470                                cp[5] =  saturateByte (scalar  % (double) cp[5]);
2471                                cp[6] =  saturateByte (scalar  % (double) cp[6]);
2472                                cp[7] =  saturateByte (scalar  % (double) cp[7]);
2473                                cp[8] =  saturateByte (scalar  % (double) cp[8]);
2474                                cp[9] =  saturateByte (scalar  % (double) cp[9]);
2475                                cp[10] =  saturateByte (scalar  % (double) cp[10]);
2476                                cp[11] =  saturateByte (scalar  % (double) cp[11]);
2477                                cp[12] =  saturateByte (scalar  % (double) cp[12]);
2478                                cp[13] =  saturateByte (scalar  % (double) cp[13]);
2479                                cp[14] =  saturateByte (scalar  % (double) cp[14]);
2480                                cp[15] =  saturateByte (scalar  % (double) cp[15]);
2481                                cp[16] =  saturateByte (scalar  % (double) cp[16]);
2482                                cp[17] =  saturateByte (scalar  % (double) cp[17]);
2483                                cp[18] =  saturateByte (scalar  % (double) cp[18]);
2484                                cp[19] =  saturateByte (scalar  % (double) cp[19]);
2485                                cp[20] =  saturateByte (scalar  % (double) cp[20]);
2486                                cp += 21; j -= 21;
2487                            }
2488                            while (j --> 0) {
2489                               
2490                                *cp =  saturateByte (scalar  % (double) *cp);
2491                                cp++;
2492                            }
2493                            break;
2494                        case BinOpItMode.SAN:
2495                            scalar = *((byte*)range.Item3);
2496                            bp = ((byte*)range.Item4 + range.Item1);
2497                            while (j > 20) {
2498                               
2499                                cp[0] =  saturateByte (scalar  % (double) bp[0]);
2500                                cp[1] =  saturateByte (scalar  % (double) bp[1]);
2501                                cp[2] =  saturateByte (scalar  % (double) bp[2]);
2502                                cp[3] =  saturateByte (scalar  % (double) bp[3]);
2503                                cp[4] =  saturateByte (scalar  % (double) bp[4]);
2504                                cp[5] =  saturateByte (scalar  % (double) bp[5]);
2505                                cp[6] =  saturateByte (scalar  % (double) bp[6]);
2506                                cp[7] =  saturateByte (scalar  % (double) bp[7]);
2507                                cp[8] =  saturateByte (scalar  % (double) bp[8]);
2508                                cp[9] =  saturateByte (scalar  % (double) bp[9]);
2509                                cp[10] =  saturateByte (scalar  % (double) bp[10]);
2510                                cp[11] =  saturateByte (scalar  % (double) bp[11]);
2511                                cp[12] =  saturateByte (scalar  % (double) bp[12]);
2512                                cp[13] =  saturateByte (scalar  % (double) bp[13]);
2513                                cp[14] =  saturateByte (scalar  % (double) bp[14]);
2514                                cp[15] =  saturateByte (scalar  % (double) bp[15]);
2515                                cp[16] =  saturateByte (scalar  % (double) bp[16]);
2516                                cp[17] =  saturateByte (scalar  % (double) bp[17]);
2517                                cp[18] =  saturateByte (scalar  % (double) bp[18]);
2518                                cp[19] =  saturateByte (scalar  % (double) bp[19]);
2519                                cp[20] =  saturateByte (scalar  % (double) bp[20]);
2520                                bp+=21; cp+=21; j -= 21;
2521                            }
2522                            while (j --> 0) {
2523                               
2524                                *cp =  saturateByte (scalar  % (double) *bp);
2525                                bp++; cp++;
2526                            }
2527                            break;
2528                        default:
2529                            break;
2530                    }
2531                    #endregion
2532                    System.Threading.Interlocked.Decrement(ref workerCount);
2533                    //retStorage.PendingEvents.Signal();
2534                };
2535
2536                #region do the work
2537                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
2538                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
2539                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
2540                        workItemLength = outLen / workItemCount;
2541                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
2542                    } else {
2543                        workItemLength = outLen / 2;
2544                        workItemCount = 2;
2545                    }
2546                } else {
2547                    workItemLength = outLen;
2548                    workItemCount = 1;
2549                }
2550               
2551                fixed ( byte* arrAP = arrA)
2552                fixed ( byte* arrBP = arrB)
2553                fixed ( byte* retArrP = retArr) {
2554
2555                    for (; i < workItemCount - 1; i++) {
2556                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
2557                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
2558                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
2559                        System.Threading.Interlocked.Increment(ref workerCount);
2560                        ILThreadPool.QueueUserWorkItem(i, worker, range);
2561                    }
2562                    // the last (or may the only) chunk is done right here
2563                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
2564                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
2565                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
2566
2567                    ILThreadPool.Wait4Workers(ref workerCount);
2568                }
2569
2570                #endregion
2571                return new  ILRetArray< byte>(retStorage);
2572            }
2573        }
2574
2575        private static unsafe ILRetArray<byte>  modEx(ILInArray<byte> A, ILInArray<byte> B) {
2576            //using (ILScope.Enter(A, B)) { we cannot start a new scope here, since this would prevent A and B to be used implace if applicable
2577
2578                #region parameter checking
2579                if (isnull(A) || isnull(B))
2580                    return empty<byte>(ILSize.Empty00);
2581                if (A.IsEmpty) {
2582                    return empty<byte>(B.S);
2583                } else if (B.IsEmpty) {
2584                    return empty<byte>(A.S);
2585                }
2586                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
2587                //    return add(A,B);
2588                int dim = -1;
2589                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
2590                    if (A.S[l] != B.S[l]) {
2591                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
2592                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
2593                        }
2594                        dim = l;
2595                    }
2596                }
2597                if (dim > 1)
2598                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
2599                dim = -(dim - 1);  // 0 -> 1, 1 -> 0
2600                #endregion
2601
2602                #region parameter preparation
2603               
2604                byte[] retArr;
2605               
2606                byte[] arrA = A.GetArrayForRead();
2607               
2608                byte[] arrB = B.GetArrayForRead();
2609                ILSize outDims;
2610                BinOptItExMode mode;
2611                int workItemMultiplierLenA;
2612                int workItemMultiplierLenB;
2613                if (A.IsVector) {
2614                    outDims = B.S;
2615                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
2616                        retArr = ILMemoryPool.Pool.New<byte>(outDims.NumberOfElements);
2617                        mode = BinOptItExMode.VAN;
2618                    } else {
2619                        mode = BinOptItExMode.VAI;
2620                    }
2621                    workItemMultiplierLenB = outDims[0];
2622                    workItemMultiplierLenA = dim;  // 0 for column, 1 for row vector
2623                } else if (B.IsVector) {
2624                    outDims = A.S;
2625                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
2626                        retArr = ILMemoryPool.Pool.New<byte>(outDims.NumberOfElements);
2627                        mode = BinOptItExMode.AVN;
2628                    } else {
2629                        mode = BinOptItExMode.AVI;
2630                    }
2631                    workItemMultiplierLenB = dim;  // 0 for column, 1 for row vector
2632                    workItemMultiplierLenA = outDims[0];
2633                } else {
2634                    throw new ILArgumentException("A and B must have the same size except for one singleton dimension in either A or B");
2635                }
2636                int itLen = outDims[0]; // (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
2637                #endregion
2638
2639                #region worker loops definition
2640                ILDenseStorage<byte> retStorage = new ILDenseStorage<byte>(retArr, outDims);
2641                int workerCount = 1;
2642                Action<object> worker = data => {
2643                    // expects: iStart, iLen, ap, bp, cp
2644                    Tuple<int, IntPtr, IntPtr, IntPtr> range =
2645                        (Tuple<int, IntPtr, IntPtr, IntPtr>)data;
2646                   
2647                    byte* ap;
2648                   
2649                    byte* bp;
2650                   
2651                    byte* cp;
2652                    switch (mode) {
2653                        case BinOptItExMode.VAN:
2654                            if (dim == 0) {
2655                                bp = (byte*)range.Item3;
2656                                cp = (byte*)range.Item4;
2657                                for (int s = 0; s < range.Item1; s++) {
2658                                    ap = (byte*)range.Item2;
2659                                    int l = itLen;
2660                                    while (l > 10) {
2661                                        cp[0] =  saturateByte (ap[0]  % (double) bp[0]);
2662                                        cp[1] =  saturateByte (ap[1]  % (double) bp[1]);
2663                                        cp[2] =  saturateByte (ap[2]  % (double) bp[2]);
2664                                        cp[3] =  saturateByte (ap[3]  % (double) bp[3]);
2665                                        cp[4] =  saturateByte (ap[4]  % (double) bp[4]);
2666                                        cp[5] =  saturateByte (ap[5]  % (double) bp[5]);
2667                                        cp[6] =  saturateByte (ap[6]  % (double) bp[6]);
2668                                        cp[7] =  saturateByte (ap[7]  % (double) bp[7]);
2669                                        cp[8] =  saturateByte (ap[8]  % (double) bp[8]);
2670                                        cp[9] =  saturateByte (ap[9]  % (double) bp[9]);
2671                                        cp[10] =  saturateByte (ap[10]  % (double) bp[10]);
2672                                        ap += 11;
2673                                        bp += 11;
2674                                        cp += 11;
2675                                        l -= 11;
2676                                    }
2677                                    while (l-- > 0) {
2678                                        *cp++ =  saturateByte (*ap++  % (double) *bp++);
2679                                    }
2680                                }
2681                            } else {
2682                                // dim == 1
2683                                ap = (byte*)range.Item2;
2684                                bp = (byte*)range.Item3;
2685                                cp = (byte*)range.Item4;
2686                                for (int s = 0; s < range.Item1; s++) {
2687                                   byte val = *ap++;
2688                                    int l = itLen;
2689                                    while (l > 10) {
2690                                        cp[0] =  saturateByte (val  % (double) bp[0]);
2691                                        cp[1] =  saturateByte (val  % (double) bp[1]);
2692                                        cp[2] =  saturateByte (val  % (double) bp[2]);
2693                                        cp[3] =  saturateByte (val  % (double) bp[3]);
2694                                        cp[4] =  saturateByte (val  % (double) bp[4]);
2695                                        cp[5] =  saturateByte (val  % (double) bp[5]);
2696                                        cp[6] =  saturateByte (val  % (double) bp[6]);
2697                                        cp[7] =  saturateByte (val  % (double) bp[7]);
2698                                        cp[8] =  saturateByte (val  % (double) bp[8]);
2699                                        cp[9] =  saturateByte (val  % (double) bp[9]);
2700                                        cp[10] =  saturateByte (val  % (double) bp[10]);
2701                                        bp += 11;
2702                                        cp += 11;
2703                                        l -= 11;
2704                                    }
2705                                    while (l-- > 0) {
2706                                        *cp++ =  saturateByte (val  % (double) *bp++);
2707                                    }
2708                                }
2709                            }
2710                            break;
2711                        case BinOptItExMode.VAI:
2712                            if (dim == 0) {
2713                                cp = (byte*)range.Item4;
2714                                for (int s = 0; s < range.Item1; s++) {
2715                                    ap = (byte*)range.Item2;
2716                                    int l = itLen;
2717                                    while (l > 10) {
2718                                        cp[0] =  saturateByte (ap[0]  % (double) cp[0]);
2719                                        cp[1] =  saturateByte (ap[1]  % (double) cp[1]);
2720                                        cp[2] =  saturateByte (ap[2]  % (double) cp[2]);
2721                                        cp[3] =  saturateByte (ap[3]  % (double) cp[3]);
2722                                        cp[4] =  saturateByte (ap[4]  % (double) cp[4]);
2723                                        cp[5] =  saturateByte (ap[5]  % (double) cp[5]);
2724                                        cp[6] =  saturateByte (ap[6]  % (double) cp[6]);
2725                                        cp[7] =  saturateByte (ap[7]  % (double) cp[7]);
2726                                        cp[8] =  saturateByte (ap[8]  % (double) cp[8]);
2727                                        cp[9] =  saturateByte (ap[9]  % (double) cp[9]);
2728                                        cp[10] =  saturateByte (ap[10]  % (double) cp[10]);
2729                                        ap += 11;
2730                                        cp += 11;
2731                                        l -= 11;
2732                                    }
2733                                    while (l-- > 0) {
2734                                        *cp =  saturateByte (*ap++  % (double) *cp);
2735                                        cp++;
2736                                    }
2737                                }
2738                            } else {
2739                                // dim == 1
2740                                cp = (byte*)range.Item4;
2741                                ap = (byte*)range.Item2;
2742                                for (int s = 0; s < range.Item1; s++) {
2743                                   
2744                                    byte val = *ap++;
2745                                    int l = itLen;
2746                                    while (l > 10) {
2747                                        cp[0] =  saturateByte (val  % (double) cp[0]);
2748                                        cp[1] =  saturateByte (val  % (double) cp[1]);
2749                                        cp[2] =  saturateByte (val  % (double) cp[2]);
2750                                        cp[3] =  saturateByte (val  % (double) cp[3]);
2751                                        cp[4] =  saturateByte (val  % (double) cp[4]);
2752                                        cp[5] =  saturateByte (val  % (double) cp[5]);
2753                                        cp[6] =  saturateByte (val  % (double) cp[6]);
2754                                        cp[7] =  saturateByte (val  % (double) cp[7]);
2755                                        cp[8] =  saturateByte (val  % (double) cp[8]);
2756                                        cp[9] =  saturateByte (val  % (double) cp[9]);
2757                                        cp[10] =  saturateByte (val  % (double) cp[10]);
2758                                        cp += 11;
2759                                        l -= 11;
2760                                    }
2761                                    while (l-- > 0) {
2762                                        *cp =  saturateByte (val  % (double) *cp);
2763                                        cp++;
2764                                    }
2765                                }
2766                            }
2767                            break;
2768                        case BinOptItExMode.AVN:
2769                            if (dim == 0) {
2770                                ap = (byte*)range.Item2;
2771                                cp = (byte*)range.Item4;
2772                                for (int s = 0; s < range.Item1; s++) {
2773                                    bp = (byte*)range.Item3;
2774                                    int l = itLen;
2775                                    while (l > 10) {
2776                                        cp[0] =  saturateByte (ap[0]  % (double) bp[0]);
2777                                        cp[1] =  saturateByte (ap[1]  % (double) bp[1]);
2778                                        cp[2] =  saturateByte (ap[2]  % (double) bp[2]);
2779                                        cp[3] =  saturateByte (ap[3]  % (double) bp[3]);
2780                                        cp[4] =  saturateByte (ap[4]  % (double) bp[4]);
2781                                        cp[5] =  saturateByte (ap[5]  % (double) bp[5]);
2782                                        cp[6] =  saturateByte (ap[6]  % (double) bp[6]);
2783                                        cp[7] =  saturateByte (ap[7]  % (double) bp[7]);
2784                                        cp[8] =  saturateByte (ap[8]  % (double) bp[8]);
2785                                        cp[9] =  saturateByte (ap[9]  % (double) bp[9]);
2786                                        cp[10] =  saturateByte (ap[10]  % (double) bp[10]);
2787                                        ap += 11;
2788                                        bp += 11;
2789                                        cp += 11;
2790                                        l -= 11;
2791                                    }
2792                                    while (l-- > 0) {
2793                                        *cp =  saturateByte (*ap  % (double) *bp);
2794                                        ap++;
2795                                        bp++;
2796                                        cp++;
2797                                    }
2798                                }
2799                            } else {
2800                                // dim = 1
2801                                ap = (byte*)range.Item2;
2802                                bp = (byte*)range.Item3;
2803                                cp = (byte*)range.Item4;
2804                                for (int s = 0; s < range.Item1; s++) {
2805                                   byte val = *bp++;
2806                                    int l = itLen;
2807                                    while (l > 10) {
2808                                        cp[0] =  saturateByte (ap[0]  % (double) val);
2809                                        cp[1] =  saturateByte (ap[1]  % (double) val);
2810                                        cp[2] =  saturateByte (ap[2]  % (double) val);
2811                                        cp[3] =  saturateByte (ap[3]  % (double) val);
2812                                        cp[4] =  saturateByte (ap[4]  % (double) val);
2813                                        cp[5] =  saturateByte (ap[5]  % (double) val);
2814                                        cp[6] =  saturateByte (ap[6]  % (double) val);
2815                                        cp[7] =  saturateByte (ap[7]  % (double) val);
2816                                        cp[8] =  saturateByte (ap[8]  % (double) val);
2817                                        cp[9] =  saturateByte (ap[9]  % (double) val);
2818                                        cp[10] =  saturateByte (ap[10]  % (double) val);
2819                                        ap += 11;
2820                                        cp += 11;
2821                                        l -= 11;
2822                                    }
2823                                    while (l-- > 0) {
2824                                        *cp =  saturateByte (*ap  % (double) val);
2825                                        ap++;
2826                                        cp++;
2827                                    }
2828                                }
2829                            }
2830                            break;
2831                        case BinOptItExMode.AVI:
2832                            if (dim == 0) {
2833                                cp = (byte*)range.Item4;
2834                                for (int s = 0; s < range.Item1; s++) {
2835                                    bp = (byte*)range.Item3;
2836                                    int l = itLen;
2837                                    while (l > 10) {
2838                                        cp[0] =  saturateByte (cp[0]  % (double) bp[0]);
2839                                        cp[1] =  saturateByte (cp[1]  % (double) bp[1]);
2840                                        cp[2] =  saturateByte (cp[2]  % (double) bp[2]);
2841                                        cp[3] =  saturateByte (cp[3]  % (double) bp[3]);
2842                                        cp[4] =  saturateByte (cp[4]  % (double) bp[4]);
2843                                        cp[5] =  saturateByte (cp[5]  % (double) bp[5]);
2844                                        cp[6] =  saturateByte (cp[6]  % (double) bp[6]);
2845                                        cp[7] =  saturateByte (cp[7]  % (double) bp[7]);
2846                                        cp[8] =  saturateByte (cp[8]  % (double) bp[8]);
2847                                        cp[9] =  saturateByte (cp[9]  % (double) bp[9]);
2848                                        cp[10] =  saturateByte (cp[10]  % (double) bp[10]);
2849                                        bp += 11;
2850                                        cp += 11;
2851                                        l -= 11;
2852                                    }
2853                                    while (l-- > 0) {
2854                                        *cp =  saturateByte (*cp  % (double) *bp);
2855                                        bp++;
2856                                        cp++;
2857                                    }
2858                                }
2859                            } else {
2860                                // dim = 1
2861                                bp = (byte*)range.Item3;
2862                                cp = (byte*)range.Item4;
2863                                for (int s = 0; s < range.Item1; s++) {
2864                                   
2865                                    byte val = *bp++;
2866                                    int l = itLen;
2867                                    while (l > 10) {
2868                                        cp[0] =  saturateByte (cp[0]  % (double) val);
2869                                        cp[1] =  saturateByte (cp[1]  % (double) val);
2870                                        cp[2] =  saturateByte (cp[2]  % (double) val);
2871                                        cp[3] =  saturateByte (cp[3]  % (double) val);
2872                                        cp[4] =  saturateByte (cp[4]  % (double) val);
2873                                        cp[5] =  saturateByte (cp[5]  % (double) val);
2874                                        cp[6] =  saturateByte (cp[6]  % (double) val);
2875                                        cp[7] =  saturateByte (cp[7]  % (double) val);
2876                                        cp[8] =  saturateByte (cp[8]  % (double) val);
2877                                        cp[9] =  saturateByte (cp[9]  % (double) val);
2878                                        cp[10] =  saturateByte (cp[10]  % (double) val);
2879                                        cp += 11;
2880                                        l -= 11;
2881                                    }
2882                                    while (l --> 0) {
2883                                        *cp =  saturateByte (*cp  % (double) val);
2884                                        cp++;
2885                                    }
2886                                }
2887                            }
2888                            break;
2889                    }
2890                    System.Threading.Interlocked.Decrement(ref workerCount);
2891                };
2892                #endregion
2893
2894                #region work distribution
2895                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
2896                if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count
2897                    && outDims[1] > 1) {
2898                        if (outDims[1] > workItemCount) {
2899                        workItemLength = outDims[1] / workItemCount;
2900                    } else {
2901                        workItemLength = outDims[1] / 2;
2902                        workItemCount = 2;
2903                    }
2904                } else {
2905                    workItemLength = outDims[1];
2906                    workItemCount = 1;
2907                }
2908
2909                fixed ( byte* arrAP = arrA)
2910                fixed ( byte* arrBP = arrB)
2911                fixed ( byte* retArrP = retArr) {
2912
2913                    for (; i < workItemCount - 1; i++) {
2914                        Tuple<int, IntPtr, IntPtr, IntPtr> range = new Tuple<int, IntPtr, IntPtr, IntPtr>
2915                               (workItemLength
2916                               , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
2917                               , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
2918                               , (IntPtr)(retArrP + i * outDims[0] * workItemLength));
2919                        System.Threading.Interlocked.Increment(ref workerCount);
2920                        ILThreadPool.QueueUserWorkItem(i, worker, range);
2921                    }
2922                    // the last (or may the only) chunk is done right here
2923                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
2924                    worker(new Tuple<int, IntPtr, IntPtr, IntPtr>
2925                                (outDims[1] - i * workItemLength
2926                                , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
2927                                , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
2928                                , (IntPtr)(retArrP + i * outDims[0] * workItemLength)));
2929
2930                    ILThreadPool.Wait4Workers(ref workerCount);
2931                }
2932                #endregion
2933
2934                return new ILRetArray<byte>(retStorage);
2935            //}  // no scopes here! it disables implace operations
2936        }
2937
2938        /// <summary>Modulus of array elements</summary>
2939        /// <param name="A">Input array A</param>
2940        /// <param name="B">Input array B</param>
2941        /// <returns>New array with result of elementwise modulus operation</returns>
2942        /// <remarks><para>On empty input an empty array will be returned.</para>
2943        /// <para>A and/or B may be scalar. The scalar value will be applied on all elements of the
2944        /// other array.</para>
2945        /// <para>If A or B is a colum vector and the other parameter is an array with a matching colum length, the vector is used to operate on all columns of the array.
2946        /// Similar, if one parameter is a row vector, it is used to operate along the rows of the other array if its number of columns matches the vector length. This feature
2947        /// can be used to replace the (costly) repmat function for most binary operators.</para>
2948        /// <para>For all other cases the dimensions of A and B must match.</para></remarks>
2949        /// <exception cref="ILNumerics.Exceptions.ILArgumentException">If the size of both arrays does not match any parameter rule.</exception>
2950        public unsafe static ILRetArray<double>  mod(ILInArray<double> A, ILInArray<double> B) {
2951            using (ILScope.Enter(A,B)) {
2952                int outLen;
2953                BinOpItMode mode;
2954                double [] retArr;
2955                double [] arrA = A.GetArrayForRead();
2956                double[] arrB = B.GetArrayForRead();
2957                ILSize outDims;
2958                #region determine operation mode
2959                if (A.IsScalar) {
2960                    outDims = B.Size;
2961                    if (B.IsScalar) {
2962                       
2963                        return new  ILRetArray<double> (new  double [1]{  (A.GetValue(0)  % B.GetValue(0))}, A.Size);
2964                    } else if (B.IsEmpty) {
2965                        return  ILRetArray<double>.empty(outDims);
2966                    } else {
2967                        outLen = outDims.NumberOfElements;
2968                        if (!B.TryGetStorage4InplaceOp(out retArr)) {
2969                            retArr = ILMemoryPool.Pool.New< double > (outLen);
2970                            mode = BinOpItMode.SAN;
2971                        } else {
2972                            mode = BinOpItMode.SAI;
2973                        }
2974                    }
2975                } else {
2976                    outDims = A.Size;
2977                    if (B.IsScalar) {
2978                        if (A.IsEmpty) {
2979                            return  ILRetArray<double>.empty(A.Size); 
2980                        }
2981                        outLen = A.S.NumberOfElements;
2982                        if (!A.TryGetStorage4InplaceOp(out retArr)) {
2983                            retArr = ILMemoryPool.Pool.New< double > (outLen);
2984                            mode = BinOpItMode.ASN;
2985                        } else {
2986                            mode = BinOpItMode.ASI;
2987                        }
2988                    } else {
2989                        // array + array
2990                        if (!A.Size.IsSameSize(B.Size)) {
2991                            return  modEx(A,B);
2992                        }
2993                        outLen = A.S.NumberOfElements;
2994                        if (A.TryGetStorage4InplaceOp(out retArr))
2995                            mode  = BinOpItMode.AAIA;
2996                        else if (B.TryGetStorage4InplaceOp(out retArr))
2997                            mode = BinOpItMode.AAIB;
2998                        else {
2999                            retArr = ILMemoryPool.Pool.New< double > (outLen);
3000                            mode = BinOpItMode.AAN;
3001                        }
3002                    }
3003                }
3004                #endregion
3005                ILDenseStorage<double> retStorage = new ILDenseStorage<double>(retArr, outDims);
3006                int i = 0, workerCount = 1;
3007                Action<object> worker = data => {
3008                    Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
3009                            = (Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>)data;
3010                    double* cp = (double*)range.Item5 + range.Item1;
3011                    double scalar;
3012                    int j = range.Item2;
3013                    #region loops
3014                    switch (mode) {
3015                        case BinOpItMode.AAIA:
3016                           double* bp = ((double*)range.Item4 + range.Item1);
3017                            while (j > 20) {
3018                                cp[0] =   (cp[0]  % bp[0]);
3019                                cp[1] =   (cp[1]  % bp[1]);
3020                                cp[2] =   (cp[2]  % bp[2]);
3021                                cp[3] =   (cp[3]  % bp[3]);
3022                                cp[4] =   (cp[4]  % bp[4]);
3023                                cp[5] =   (cp[5]  % bp[5]);
3024                                cp[6] =   (cp[6]  % bp[6]);
3025                                cp[7] =   (cp[7]  % bp[7]);
3026                                cp[8] =   (cp[8]  % bp[8]);
3027                                cp[9] =   (cp[9]  % bp[9]);
3028                                cp[10] =   (cp[10]  % bp[10]);
3029                                cp[11] =   (cp[11]  % bp[11]);
3030                                cp[12] =   (cp[12]  % bp[12]);
3031                                cp[13] =   (cp[13]  % bp[13]);
3032                                cp[14] =   (cp[14]  % bp[14]);
3033                                cp[15] =   (cp[15]  % bp[15]);
3034                                cp[16] =   (cp[16]  % bp[16]);
3035                                cp[17] =   (cp[17]  % bp[17]);
3036                                cp[18] =   (cp[18]  % bp[18]);
3037                                cp[19] =   (cp[19]  % bp[19]);
3038                                cp[20] =   (cp[20]  % bp[20]);
3039                                cp += 21; bp += 21; j -= 21;
3040                            }
3041                            while (j --> 0) {
3042                               
3043                                *cp =   (*cp  % *bp);
3044                                cp++; bp++;
3045                            }
3046                            break;
3047                        case BinOpItMode.AAIB:
3048                           double* ap = ((double*)range.Item3 + range.Item1);
3049                            while (j > 20) {
3050                               
3051                                cp[0] =   (ap[0]  % cp[0]);
3052                                cp[1] =   (ap[1]  % cp[1]);
3053                                cp[2] =   (ap[2]  % cp[2]);
3054                                cp[3] =   (ap[3]  % cp[3]);
3055                                cp[4] =   (ap[4]  % cp[4]);
3056                                cp[5] =   (ap[5]  % cp[5]);
3057                                cp[6] =   (ap[6]  % cp[6]);
3058                                cp[7] =   (ap[7]  % cp[7]);
3059                                cp[8] =   (ap[8]  % cp[8]);
3060                                cp[9] =   (ap[9]  % cp[9]);
3061                                cp[10] =   (ap[10]  % cp[10]);
3062                                cp[11] =   (ap[11]  % cp[11]);
3063                                cp[12] =   (ap[12]  % cp[12]);
3064                                cp[13] =   (ap[13]  % cp[13]);
3065                                cp[14] =   (ap[14]  % cp[14]);
3066                                cp[15] =   (ap[15]  % cp[15]);
3067                                cp[16] =   (ap[16]  % cp[16]);
3068                                cp[17] =   (ap[17]  % cp[17]);
3069                                cp[18] =   (ap[18]  % cp[18]);
3070                                cp[19] =   (ap[19]  % cp[19]);
3071                                cp[20] =   (ap[20]  % cp[20]);
3072                                ap += 21; cp += 21; j -= 21;
3073                            }
3074                            while (j --> 0) {
3075                               
3076                                *cp =   (*ap  % *cp);
3077                                ap++; cp++;
3078                            }
3079                            break;
3080                        case BinOpItMode.AAN:
3081                            ap = ((double*)range.Item3 + range.Item1);
3082                            bp = ((double*)range.Item4 + range.Item1);
3083                            while (j > 20) {
3084                               
3085                                cp[0] =   (ap[0]  % bp[0]);
3086                                cp[1] =   (ap[1]  % bp[1]);
3087                                cp[2] =   (ap[2]  % bp[2]);
3088                                cp[3] =   (ap[3]  % bp[3]);
3089                                cp[4] =   (ap[4]  % bp[4]);
3090                                cp[5] =   (ap[5]  % bp[5]);
3091                                cp[6] =   (ap[6]  % bp[6]);
3092                                cp[7] =   (ap[7]  % bp[7]);
3093                                cp[8] =   (ap[8]  % bp[8]);
3094                                cp[9] =   (ap[9]  % bp[9]);
3095                                cp[10] =   (ap[10]  % bp[10]);
3096                                cp[11] =   (ap[11]  % bp[11]);
3097                                cp[12] =   (ap[12]  % bp[12]);
3098                                cp[13] =   (ap[13]  % bp[13]);
3099                                cp[14] =   (ap[14]  % bp[14]);
3100                                cp[15] =   (ap[15]  % bp[15]);
3101                                cp[16] =   (ap[16]  % bp[16]);
3102                                cp[17] =   (ap[17]  % bp[17]);
3103                                cp[18] =   (ap[18]  % bp[18]);
3104                                cp[19] =   (ap[19]  % bp[19]);
3105                                cp[20] =   (ap[20]  % bp[20]);
3106                                ap+=21; bp+=21; cp+=21; j-=21;
3107                            }
3108                            while (j --> 0) {
3109                               
3110                                *cp =   (*ap  % *bp);
3111                                ap++; bp++; cp++;
3112                            }
3113                            break;
3114                        case BinOpItMode.ASI:
3115                            scalar = *((double*)range.Item4);
3116                            while (j > 20) {
3117                               
3118                                cp[0] =   (cp[0]  % scalar);
3119                                cp[1] =   (cp[1]  % scalar);
3120                                cp[2] =   (cp[2]  % scalar);
3121                                cp[3] =   (cp[3]  % scalar);
3122                                cp[4] =   (cp[4]  % scalar);
3123                                cp[5] =   (cp[5]  % scalar);
3124                                cp[6] =   (cp[6]  % scalar);
3125                                cp[7] =   (cp[7]  % scalar);
3126                                cp[8] =   (cp[8]  % scalar);
3127                                cp[9] =   (cp[9]  % scalar);
3128                                cp[10] =   (cp[10]  % scalar);
3129                                cp[11] =   (cp[11]  % scalar);
3130                                cp[12] =   (cp[12]  % scalar);
3131                                cp[13] =   (cp[13]  % scalar);
3132                                cp[14] =   (cp[14]  % scalar);
3133                                cp[15] =   (cp[15]  % scalar);
3134                                cp[16] =   (cp[16]  % scalar);
3135                                cp[17] =   (cp[17]  % scalar);
3136                                cp[18] =   (cp[18]  % scalar);
3137                                cp[19] =   (cp[19]  % scalar);
3138                                cp[20] =   (cp[20]  % scalar);
3139                                cp += 21; j -= 21;
3140                            }
3141                            while (j --> 0) {
3142                               
3143                                *cp =   (*cp  % scalar);
3144                                cp++;
3145                            }
3146                            break;
3147                        case BinOpItMode.ASN:
3148                            ap = ((double*)range.Item3 + range.Item1);
3149                            scalar = *((double*)range.Item4);
3150                            while (j > 20) {
3151                               
3152                                cp[0] =   (ap[0]  % scalar);
3153                                cp[1] =   (ap[1]  % scalar);
3154                                cp[2] =   (ap[2]  % scalar);
3155                                cp[3] =   (ap[3]  % scalar);
3156                                cp[4] =   (ap[4]  % scalar);
3157                                cp[5] =   (ap[5]  % scalar);
3158                                cp[6] =   (ap[6]  % scalar);
3159                                cp[7] =   (ap[7]  % scalar);
3160                                cp[8] =   (ap[8]  % scalar);
3161                                cp[9] =   (ap[9]  % scalar);
3162                                cp[10] =   (ap[10]  % scalar);
3163                                cp[11] =   (ap[11]  % scalar);
3164                                cp[12] =   (ap[12]  % scalar);
3165                                cp[13] =   (ap[13]  % scalar);
3166                                cp[14] =   (ap[14]  % scalar);
3167                                cp[15] =   (ap[15]  % scalar);
3168                                cp[16] =   (ap[16]  % scalar);
3169                                cp[17] =   (ap[17]  % scalar);
3170                                cp[18] =   (ap[18]  % scalar);
3171                                cp[19] =   (ap[19]  % scalar);
3172                                cp[20] =   (ap[20]  % scalar);
3173                                ap+=21; cp+=21; j -= 21;
3174                            }
3175                            while (j --> 0) {
3176                               
3177                                *cp =   (*ap  % scalar);
3178                                ap++; cp++;
3179                            }
3180                            break;
3181                        case BinOpItMode.SAI:
3182                            scalar = *((double*)range.Item3);
3183                            while (j > 20) {
3184                               
3185                                cp[0] =   (scalar  % cp[0]);
3186                                cp[1] =   (scalar  % cp[1]);
3187                                cp[2] =   (scalar  % cp[2]);
3188                                cp[3] =   (scalar  % cp[3]);
3189                                cp[4] =   (scalar  % cp[4]);
3190                                cp[5] =   (scalar  % cp[5]);
3191                                cp[6] =   (scalar  % cp[6]);
3192                                cp[7] =   (scalar  % cp[7]);
3193                                cp[8] =   (scalar  % cp[8]);
3194                                cp[9] =   (scalar  % cp[9]);
3195                                cp[10] =   (scalar  % cp[10]);
3196                                cp[11] =   (scalar  % cp[11]);
3197                                cp[12] =   (scalar  % cp[12]);
3198                                cp[13] =   (scalar  % cp[13]);
3199                                cp[14] =   (scalar  % cp[14]);
3200                                cp[15] =   (scalar  % cp[15]);
3201                                cp[16] =   (scalar  % cp[16]);
3202                                cp[17] =   (scalar  % cp[17]);
3203                                cp[18] =   (scalar  % cp[18]);
3204                                cp[19] =   (scalar  % cp[19]);
3205                                cp[20] =   (scalar  % cp[20]);
3206                                cp += 21; j -= 21;
3207                            }
3208                            while (j --> 0) {
3209                               
3210                                *cp =   (scalar  % *cp);
3211                                cp++;
3212                            }
3213                            break;
3214                        case BinOpItMode.SAN:
3215                            scalar = *((double*)range.Item3);
3216                            bp = ((double*)range.Item4 + range.Item1);
3217                            while (j > 20) {
3218                               
3219                                cp[0] =   (scalar  % bp[0]);
3220                                cp[1] =   (scalar  % bp[1]);
3221                                cp[2] =   (scalar  % bp[2]);
3222                                cp[3] =   (scalar  % bp[3]);
3223                                cp[4] =   (scalar  % bp[4]);
3224                                cp[5] =   (scalar  % bp[5]);
3225                                cp[6] =   (scalar  % bp[6]);
3226                                cp[7] =   (scalar  % bp[7]);
3227                                cp[8] =   (scalar  % bp[8]);
3228                                cp[9] =   (scalar  % bp[9]);
3229                                cp[10] =   (scalar  % bp[10]);
3230                                cp[11] =   (scalar  % bp[11]);
3231                                cp[12] =   (scalar  % bp[12]);
3232                                cp[13] =   (scalar  % bp[13]);
3233                                cp[14] =   (scalar  % bp[14]);
3234                                cp[15] =   (scalar  % bp[15]);
3235                                cp[16] =   (scalar  % bp[16]);
3236                                cp[17] =   (scalar  % bp[17]);
3237                                cp[18] =   (scalar  % bp[18]);
3238                                cp[19] =   (scalar  % bp[19]);
3239                                cp[20] =   (scalar  % bp[20]);
3240                                bp+=21; cp+=21; j -= 21;
3241                            }
3242                            while (j --> 0) {
3243                               
3244                                *cp =   (scalar  % *bp);
3245                                bp++; cp++;
3246                            }
3247                            break;
3248                        default:
3249                            break;
3250                    }
3251                    #endregion
3252                    System.Threading.Interlocked.Decrement(ref workerCount);
3253                    //retStorage.PendingEvents.Signal();
3254                };
3255
3256                #region do the work
3257                int workItemCount = Settings.s_maxNumberThreads, workItemLength;
3258                if (Settings.s_maxNumberThreads > 1 && outLen / 2 > Settings.s_minParallelElement1Count) {
3259                    if (outLen / workItemCount > Settings.s_minParallelElement1Count) {
3260                        workItemLength = outLen / workItemCount;
3261                        //workItemLength = (int)((double)outLen / workItemCount * 1.05);
3262                    } else {
3263                        workItemLength = outLen / 2;
3264                        workItemCount = 2;
3265                    }
3266                } else {
3267                    workItemLength = outLen;
3268                    workItemCount = 1;
3269                }
3270               
3271                fixed ( double* arrAP = arrA)
3272                fixed ( double* arrBP = arrB)
3273                fixed ( double* retArrP = retArr) {
3274
3275                    for (; i < workItemCount - 1; i++) {
3276                        Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode> range
3277                            = new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
3278                                (i * workItemLength, workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode);
3279                        System.Threading.Interlocked.Increment(ref workerCount);
3280                        ILThreadPool.QueueUserWorkItem(i, worker, range);
3281                    }
3282                    // the last (or may the only) chunk is done right here
3283                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
3284                    worker(new Tuple<int, int, IntPtr, IntPtr, IntPtr, BinOpItMode>
3285                                (i * workItemLength, outLen - i * workItemLength, (IntPtr)arrAP, (IntPtr)arrBP, (IntPtr)retArrP, mode));
3286
3287                    ILThreadPool.Wait4Workers(ref workerCount);
3288                }
3289
3290                #endregion
3291                return new  ILRetArray< double>(retStorage);
3292            }
3293        }
3294
3295        private static unsafe ILRetArray<double>  modEx(ILInArray<double> A, ILInArray<double> B) {
3296            //using (ILScope.Enter(A, B)) { we cannot start a new scope here, since this would prevent A and B to be used implace if applicable
3297
3298                #region parameter checking
3299                if (isnull(A) || isnull(B))
3300                    return empty<double>(ILSize.Empty00);
3301                if (A.IsEmpty) {
3302                    return empty<double>(B.S);
3303                } else if (B.IsEmpty) {
3304                    return empty<double>(A.S);
3305                }
3306                //if (A.IsScalar || B.IsScalar || A.D.IsSameSize(B.D))
3307                //    return add(A,B);
3308                int dim = -1;
3309                for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) {
3310                    if (A.S[l] != B.S[l]) {
3311                        if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) {
3312                            throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B");
3313                        }
3314                        dim = l;
3315                    }
3316                }
3317                if (dim > 1)
3318                    throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors");
3319                dim = -(dim - 1);  // 0 -> 1, 1 -> 0
3320                #endregion
3321
3322                #region parameter preparation
3323               
3324                double[] retArr;
3325               
3326                double[] arrA = A.GetArrayForRead();
3327               
3328                double[] arrB = B.GetArrayForRead();
3329                ILSize outDims;
3330                BinOptItExMode mode;
3331                int workItemMultiplierLenA;
3332                int workItemMultiplierLenB;
3333                if (A.IsVector) {
3334                    outDims = B.S;
3335                    if (!B.TryGetStorage4InplaceOp(out retArr)) {
3336                        retArr = ILMemoryPool.Pool.New<double>(outDims.NumberOfElements);
3337                        mode = BinOptItExMode.VAN;
3338                    } else {
3339                        mode = BinOptItExMode.VAI;
3340                    }
3341                    workItemMultiplierLenB = outDims[0];
3342                    workItemMultiplierLenA = dim;  // 0 for column, 1 for row vector
3343                } else if (B.IsVector) {
3344                    outDims = A.S;
3345                    if (!A.TryGetStorage4InplaceOp(out retArr)) {
3346                        retArr = ILMemoryPool.Pool.New<double>(outDims.NumberOfElements);
3347                        mode = BinOptItExMode.AVN;
3348                    } else {
3349                        mode = BinOptItExMode.AVI;
3350                    }
3351                    workItemMultiplierLenB = dim;  // 0 for column, 1 for row vector
3352                    workItemMultiplierLenA = outDims[0];
3353                } else {
3354                    throw new ILArgumentException("A and B must have the same size except for one singleton dimension in either A or B");
3355                }
3356                int itLen = outDims[0]; // (dim == 0) ? outDims.SequentialIndexDistance(1) : outDims.SequentialIndexDistance(0);
3357                #endregion
3358
3359                #region worker loops definition
3360                ILDenseStorage<double> retStorage = new ILDenseStorage<double>(retArr, outDims);
3361                int workerCount = 1;
3362                Action<object> worker = data => {
3363                    // expects: iStart, iLen, ap, bp, cp
3364                    Tuple<int, IntPtr, IntPtr, IntPtr> range =
3365                        (Tuple<int, IntPtr, IntPtr, IntPtr>)data;
3366                   
3367                    double* ap;
3368                   
3369                    double* bp;
3370                   
3371                    double* cp;
3372                    switch (mode) {
3373                        case BinOptItExMode.VAN:
3374                            if (dim == 0) {
3375                                bp = (double*)range.Item3;
3376                                cp = (double*)range.Item4;
3377                                for (int s = 0; s < range.Item1; s++) {
3378                                    ap = (double*)range.Item2;
3379                                    int l = itLen;
3380                                    while (l > 10) {
3381                                        cp[0] =   (ap[0]  % bp[0]);
3382                                        cp[1] =   (ap[1]  % bp[1]);
3383                                        cp[2] =   (ap[2]  % bp[2]);
3384                                        cp[3] =   (ap[3]  % bp[3]);
3385                                        cp[4] =   (ap[4]  % bp[4]);
3386                                        cp[5] =   (ap[5]  % bp[5]);
3387                                        cp[6] =   (ap[6]  % bp[6]);
3388                                        cp[7] =   (ap[7]  % bp[7]);
3389                                        cp[8] =   (ap[8]  % bp[8]);
3390                                        cp[9] =   (ap[9]  % bp[9]);
3391                                        cp[10] =   (ap[10]  % bp[10]);
3392                                        ap += 11;
3393                                        bp += 11;
3394                                        cp += 11;
3395                                        l -= 11;
3396                                    }
3397                                    while (l-- > 0) {
3398                                        *cp++ =   (*ap++  % *bp++);
3399                                    }
3400                                }
3401                            } else {
3402                                // dim == 1
3403                                ap = (double*)range.Item2;
3404                                bp = (double*)range.Item3;
3405                                cp = (double*)range.Item4;
3406                                for (int s = 0; s < range.Item1; s++) {
3407                                   double val = *ap++;
3408                                    int l = itLen;
3409                                    while (l > 10) {
3410                                        cp[0] =   (val  % bp[0]);
3411                                        cp[1] =   (val  % bp[1]);
3412                                        cp[2] =   (val  % bp[2]);
3413                                        cp[3] =   (val  % bp[3]);
3414                                        cp[4] =   (val  % bp[4]);
3415                                        cp[5] =   (val  % bp[5]);
3416                                        cp[6] =   (val  % bp[6]);
3417                                        cp[7] =   (val  % bp[7]);
3418                                        cp[8] =   (val  % bp[8]);
3419                                        cp[9] =   (val  % bp[9]);
3420                                        cp[10] =   (val  % bp[10]);
3421                                        bp += 11;
3422                                        cp += 11;
3423                                        l -= 11;
3424                                    }
3425                                    while (l-- > 0) {
3426                                        *cp++ =   (val  % *bp++);
3427                                    }
3428                                }
3429                            }
3430                            break;
3431                        case BinOptItExMode.VAI:
3432                            if (dim == 0) {
3433                                cp = (double*)range.Item4;
3434                                for (int s = 0; s < range.Item1; s++) {
3435                                    ap = (double*)range.Item2;
3436                                    int l = itLen;
3437                                    while (l > 10) {
3438                                        cp[0] =   (ap[0]  % cp[0]);
3439                                        cp[1] =   (ap[1]  % cp[1]);
3440                                        cp[2] =   (ap[2]  % cp[2]);
3441                                        cp[3] =   (ap[3]  % cp[3]);
3442                                        cp[4] =   (ap[4]  % cp[4]);
3443                                        cp[5] =   (ap[5]  % cp[5]);
3444                                        cp[6] =   (ap[6]  % cp[6]);
3445                                        cp[7] =   (ap[7]  % cp[7]);
3446                                        cp[8] =   (ap[8]  % cp[8]);
3447                                        cp[9] =   (ap[9]  % cp[9]);
3448                                        cp[10] =   (ap[10]  % cp[10]);
3449                                        ap += 11;
3450                                        cp += 11;
3451                                        l -= 11;
3452                                    }
3453                                    while (l-- > 0) {
3454                                        *cp =   (*ap++  % *cp);
3455                                        cp++;
3456                                    }
3457                                }
3458                            } else {
3459                                // dim == 1
3460                                cp = (double*)range.Item4;
3461                                ap = (double*)range.Item2;
3462                                for (int s = 0; s < range.Item1; s++) {
3463                                   
3464                                    double val = *ap++;
3465                                    int l = itLen;
3466                                    while (l > 10) {
3467                                        cp[0] =   (val  % cp[0]);
3468                                        cp[1] =   (val  % cp[1]);
3469                                        cp[2] =   (val  % cp[2]);
3470                                        cp[3] =   (val  % cp[3]);
3471                                        cp[4] =   (val  % cp[4]);
3472                                        cp[5] =   (val  % cp[5]);
3473                                        cp[6] =   (val  % cp[6]);
3474                                        cp[7] =   (val  % cp[7]);
3475                                        cp[8] =   (val  % cp[8]);
3476                                        cp[9] =   (val  % cp[9]);
3477                                        cp[10] =   (val  % cp[10]);
3478                                        cp += 11;
3479                                        l -= 11;
3480                                    }
3481                                    while (l-- > 0) {
3482                                        *cp =   (val  % *cp);
3483                                        cp++;
3484                                    }
3485                                }
3486                            }
3487                            break;
3488                        case BinOptItExMode.AVN:
3489                            if (dim == 0) {
3490                                ap = (double*)range.Item2;
3491                                cp = (double*)range.Item4;
3492                                for (int s = 0; s < range.Item1; s++) {
3493                                    bp = (double*)range.Item3;
3494                                    int l = itLen;
3495                                    while (l > 10) {
3496                                        cp[0] =   (ap[0]  % bp[0]);
3497                                        cp[1] =   (ap[1]  % bp[1]);
3498                                        cp[2] =   (ap[2]  % bp[2]);
3499                                        cp[3] =   (ap[3]  % bp[3]);
3500                                        cp[4] =   (ap[4]  % bp[4]);
3501                                        cp[5] =   (ap[5]  % bp[5]);
3502                                        cp[6] =   (ap[6]  % bp[6]);
3503                                        cp[7] =   (ap[7]  % bp[7]);
3504                                        cp[8] =   (ap[8]  % bp[8]);
3505                                        cp[9] =   (ap[9]  % bp[9]);
3506                                        cp[10] =   (ap[10]  % bp[10]);
3507                                        ap += 11;
3508                                        bp += 11;
3509                                        cp += 11;
3510                                        l -= 11;
3511                                    }
3512                                    while (l-- > 0) {
3513                                        *cp =   (*ap  % *bp);
3514                                        ap++;
3515                                        bp++;
3516                                        cp++;
3517                                    }
3518                                }
3519                            } else {
3520                                // dim = 1
3521                                ap = (double*)range.Item2;
3522                                bp = (double*)range.Item3;
3523                                cp = (double*)range.Item4;
3524                                for (int s = 0; s < range.Item1; s++) {
3525                                   double val = *bp++;
3526                                    int l = itLen;
3527                                    while (l > 10) {
3528                                        cp[0] =   (ap[0]  % val);
3529                                        cp[1] =   (ap[1]  % val);
3530                                        cp[2] =   (ap[2]  % val);
3531                                        cp[3] =   (ap[3]  % val);
3532                                        cp[4] =   (ap[4]  % val);
3533                                        cp[5] =   (ap[5]  % val);
3534                                        cp[6] =   (ap[6]  % val);
3535                                        cp[7] =   (ap[7]  % val);
3536                                        cp[8] =   (ap[8]  % val);
3537                                        cp[9] =   (ap[9]  % val);
3538                                        cp[10] =   (ap[10]  % val);
3539                                        ap += 11;
3540                                        cp += 11;
3541                                        l -= 11;
3542                                    }
3543                                    while (l-- > 0) {
3544                                        *cp =   (*ap  % val);
3545                                        ap++;
3546                                        cp++;
3547                                    }
3548                                }
3549                            }
3550                            break;
3551                        case BinOptItExMode.AVI:
3552                            if (dim == 0) {
3553                                cp = (double*)range.Item4;
3554                                for (int s = 0; s < range.Item1; s++) {
3555                                    bp = (double*)range.Item3;
3556                                    int l = itLen;
3557                                    while (l > 10) {
3558                                        cp[0] =   (cp[0]  % bp[0]);
3559                                        cp[1] =   (cp[1]  % bp[1]);
3560                                        cp[2] =   (cp[2]  % bp[2]);
3561                                        cp[3] =   (cp[3]  % bp[3]);
3562                                        cp[4] =   (cp[4]  % bp[4]);
3563                                        cp[5] =   (cp[5]  % bp[5]);
3564                                        cp[6] =   (cp[6]  % bp[6]);
3565                                        cp[7] =   (cp[7]  % bp[7]);
3566                                        cp[8] =   (cp[8]  % bp[8]);
3567                                        cp[9] =   (cp[9]  % bp[9]);
3568                                        cp[10] =   (cp[10]  % bp[10]);
3569                                        bp += 11;
3570                                        cp += 11;
3571                                        l -= 11;
3572                                    }
3573                                    while (l-- > 0) {
3574                                        *cp =   (*cp  % *bp);
3575                                        bp++;
3576                                        cp++;
3577                                    }
3578                                }
3579                            } else {
3580                                // dim = 1
3581                                bp = (double*)range.Item3;
3582                                cp = (double*)range.Item4;
3583                                for (int s = 0; s < range.Item1; s++) {
3584                                   
3585                                    double val = *bp++;
3586                                    int l = itLen;
3587                                    while (l > 10) {
3588                                        cp[0] =   (cp[0]  % val);
3589                                        cp[1] =   (cp[1]  % val);
3590                                        cp[2] =   (cp[2]  % val);
3591                                        cp[3] =   (cp[3]  % val);
3592                                        cp[4] =   (cp[4]  % val);
3593                                        cp[5] =   (cp[5]  % val);
3594                                        cp[6] =   (cp[6]  % val);
3595                                        cp[7] =   (cp[7]  % val);
3596                                        cp[8] =   (cp[8]  % val);
3597                                        cp[9] =   (cp[9]  % val);
3598                                        cp[10] =   (cp[10]  % val);
3599                                        cp += 11;
3600                                        l -= 11;
3601                                    }
3602                                    while (l --> 0) {
3603                                        *cp =   (*cp  % val);
3604                                        cp++;
3605                                    }
3606                                }
3607                            }
3608                            break;
3609                    }
3610                    System.Threading.Interlocked.Decrement(ref workerCount);
3611                };
3612                #endregion
3613
3614                #region work distribution
3615                int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength;
3616                if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count
3617                    && outDims[1] > 1) {
3618                        if (outDims[1] > workItemCount) {
3619                        workItemLength = outDims[1] / workItemCount;
3620                    } else {
3621                        workItemLength = outDims[1] / 2;
3622                        workItemCount = 2;
3623                    }
3624                } else {
3625                    workItemLength = outDims[1];
3626                    workItemCount = 1;
3627                }
3628
3629                fixed ( double* arrAP = arrA)
3630                fixed ( double* arrBP = arrB)
3631                fixed ( double* retArrP = retArr) {
3632
3633                    for (; i < workItemCount - 1; i++) {
3634                        Tuple<int, IntPtr, IntPtr, IntPtr> range = new Tuple<int, IntPtr, IntPtr, IntPtr>
3635                               (workItemLength
3636                               , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
3637                               , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
3638                               , (IntPtr)(retArrP + i * outDims[0] * workItemLength));
3639                        System.Threading.Interlocked.Increment(ref workerCount);
3640                        ILThreadPool.QueueUserWorkItem(i, worker, range);
3641                    }
3642                    // the last (or may the only) chunk is done right here
3643                    //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks);
3644                    worker(new Tuple<int, IntPtr, IntPtr, IntPtr>
3645                                (outDims[1] - i * workItemLength
3646                                , (IntPtr)(arrAP + i * workItemMultiplierLenA * workItemLength)
3647                                , (IntPtr)(arrBP + i * workItemMultiplierLenB * workItemLength)
3648                                , (IntPtr)(retArrP + i * outDims[0] * workItemLength)));
3649
3650                    ILThreadPool.Wait4Workers(ref workerCount);
3651                }
3652                #endregion
3653
3654                return new ILRetArray<double>(retStorage);
3655            //}  // no scopes here! it disables implace operations
3656        }
3657
3658
3659#endregion HYCALPER AUTO GENERATED CODE
3660
3661    }
3662}
Note: See TracBrowser for help on using the repository browser.