08 December 2020, 17:32 | #1 |
<optimized out>
Join Date: Sep 2020
Location: <optimized out>
Posts: 321
|
Alternatives to using % operator to wrap around the end of an array?
I'm trying to make sensible optimisations to a code base that does a lot of operations on elements in arrays that need to "wrap around", i.e. the operation on the last element needs to include the first element. These are mostly algorithms that need to visit every directed edge of a polygon, so the last edge is given by the last and first vertices. There are other examples, but it's mostly this.
Up till now, to make sure the last edge is (n - 1) to (0), I've been using the % operator. This effects performance because it's just a division in disguise. So, how to fix? I've come up with three options, below, none of which really make me feel happy. I'm currently using Option A, but I can't live with code like that. Option B looks like it might be efficient, but doesn't feel nice. Option 3 feels like it might be efficient but adds complexity that I feel a simple problem like this doesn't warrant. Are there any options I've overlooked? My priorities are efficiency without complexity that hides the intent of the code, and sticking to what's available in C99. Here are the options I've considered in code. The arrays elements are typically pointers to structures, but I think this gives the essence. Code:
Original: --------- for (int i = 0; i < n; i++) { int a = x[i]; int b = x[(i + 1) % n]; // do something with a and b } Option A: Copy and Paste ------------------------ for (int i = 0; i < n - 1; i++) { int a = x[i]; int b = x[i + 1]; // do something with a and b } { int a = x[n - 1]; int b = x[0]; // do something with a and b } Option B: Repeat the First Element ---------------------------------- x[n] = x[0]; for (int i = 0; i < n; i++) { int a = x[i]; int b = x[i + 1]; // do something with a and b } Option 3: Some Pointers ----------------------- int * p = &x[0]; int * q = &x[n - 1]; for (int i = 0; i < n; i++) { int a = *p; int b = *q; // do something with a and b q = p; p++; } |
08 December 2020, 18:25 | #2 |
Registered User
Join Date: Jan 2002
Location: Germany
Posts: 7,002
|
If the size of the array is a power of two you could use the & operator instead of %.
Code:
int n = 1 << 8; int mask = n - 1; for (int i = 0; i < n; i++) { int a = x[i]; int b = x[(i + 1) & mask]; // do something with a and b } |
08 December 2020, 18:36 | #3 |
<optimized out>
Join Date: Sep 2020
Location: <optimized out>
Posts: 321
|
|
08 December 2020, 18:38 | #4 |
This cat is no more
Join Date: Dec 2004
Location: FRANCE
Age: 52
Posts: 8,206
|
You cannot got much past the array. Only 1, which would wrap to 0 with the modulus. So you can simply access with a ternary expression:
Code:
x[i < (n-1) ? (i+1) : 0] Last edited by jotd; 08 December 2020 at 18:45. |
08 December 2020, 18:46 | #5 | |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,233
|
Quote:
Repeating the first element is ok as long as you can ensure that you keep the data structure consistent. The problem here might be that you forget updating the elements accordingly. C has a penalty as well, namely one additional level of indirection. Depending on the processor, this may or may not be more costly than the division. Does the order of elements matter? Are there at least 2 elements in the array? If not, then there is a nice solution with pointers rather than indices: Code:
xp = &x[0]; lp = &x[n]; last = lp[-1]; do { current = *xp; do(current,last); last = current; xp++; } while(xp < lp); |
|
08 December 2020, 18:59 | #6 | ||
<optimized out>
Join Date: Sep 2020
Location: <optimized out>
Posts: 321
|
Quote:
Quote:
last = lp[-1];allowed? Thanks. |
||
08 December 2020, 19:00 | #7 |
This cat is no more
Join Date: Dec 2004
Location: FRANCE
Age: 52
Posts: 8,206
|
lp[-1] is just *(lp-1) so it's pointer arithmetic and it's allowed.
|
08 December 2020, 19:15 | #8 |
<optimized out>
Join Date: Sep 2020
Location: <optimized out>
Posts: 321
|
|
15 December 2020, 15:37 | #9 |
Registered User
Join Date: Sep 2019
Location: Essen/Germany
Age: 55
Posts: 463
|
Is the array index any value, or do you just want to wrap around?
If you just want to wrap around, you can use: wrap = ARRAYSIZE - index This works only as long as index is smaller than twice arraysize. |
15 December 2020, 16:16 | #10 | |
<optimized out>
Join Date: Sep 2020
Location: <optimized out>
Posts: 321
|
Quote:
I tried Mr Richter's solution but ended up settling on my original Option 3. His solution is definitely better, but I had to stop and think when reading my implementation of it. |
|
15 December 2020, 16:51 | #11 |
Registered User
Join Date: Sep 2019
Location: Essen/Germany
Age: 55
Posts: 463
|
I just noticed that my solution doesn't really work, because if index is outside the range, then you get a negative index.
|
15 December 2020, 17:19 | #12 |
<optimized out>
Join Date: Sep 2020
Location: <optimized out>
Posts: 321
|
|
15 December 2020, 17:46 | #13 |
Registered User
Join Date: Sep 2019
Location: Essen/Germany
Age: 55
Posts: 463
|
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Illegal Operator opt c-,ow, o+ | W4r3DeV1L | Coders. General | 5 | 23 September 2019 20:45 |
Creating an array gives me a Guru | Shatterhand | Coders. Blitz Basic | 14 | 13 August 2019 20:54 |
Illegal Operator on Include | marduk_kurios | Coders. Asm / Hardware | 8 | 04 August 2017 20:09 |
Strange AsmOne operator | phx | Coders. Asm / Hardware | 23 | 18 March 2015 23:13 |
In game screen grab & Wrap around | Retro1234 | request.Other | 0 | 09 September 2011 19:08 |
|
|