For instance if you have an int array that contains the numbers 1-250 and you index with a uint8 variable i,
for (uint8 i = 247; i++;) {
// print circ_arr[i]
}
for the values of i near the overflow points of the circular array and of the uint8 it gets weird: i circ_arr[i]
247 247
248 248
249 249
250 250
251 1 # 251 % 250 = 0
252 2 # 252 % 250 = 1
253 3 # ...
254 4
255 5
0 1 # i overflows to 0
1 2
...If you're indexing with a [u]int32 you need to worry about this once every 4 billion increments, and if an incomplete cycle is a show-stopper for you, you can compute a safe modulo yourself based on the size(s) of your circular array(s), but more likely you just need something else. But really, you don't care if your cache hiccups a little once every 4 billion caches.
You make a good point, of course, I'm just allergic to people poking holes in back-of-the-napkin explanations of things with the trite "but integers can overflow!" It's one of those most common well actuallys written on this site. Of course integers can overflow. They almost never do though, do they? And if they do, a test fails and you add a single line somewhere to fix it.
I really think the vast majority of programmers are too often thinking about bits when they should be thinking about math.
You’d need a way to get that type, for example as
float a[10,20] // two-dimensional array of floats
typeof(a.dims(0)) i = 0 // modular type with values in [0,9]
typeof(a.dims(1)) j = 0 // modular type with values in [0,19]
or, slightly neater: auto i = a.indextype(0)
auto j = a.indextype(1)
Ugly syntax, but in a modern language, most code would probably do something like for (i,j,value) in a
where the types are inferred.Having those modular types means the compiler would do the arithmetic correct for the array, while the negative literals allow programmers to specify “last” and “next to last” correctly.
That's something I'd like in a bunch of languages - a real modulo operator that always returns between 0 and n, even for negative inputs, rather than a remainder operator that's advertised as a modulo operator. Grrrrr!!!!!
Expression<Func<int, int>> lambda = n => n % 2;
Console.WriteLine(((dynamic)lambda).Body.NodeType);
Output is "Modulo".Ada has both rem and mod operatiors. I'm not sure how many other languages have operators for both.
I do think it's quite odd and frustrating that modulo can return negative numbers and I don't really get the reasoning there, but there's probably a good reason I don't know about.
I'm not sure I'd want it for every list, but there are certain places it's nice.
[1] https://www.allaboutcircuits.com/technical-articles/circular...
Directly, it supports caches very well. You just increment the number of things you've ever cached and that's where your next cached value goes; you don't care when it overwrites an old value.
There are other cases where you just need some variant of a thing, but you don't actually care that much about which variant you get. You might want to vary your wording in auto-generated text, for instance, by rotating synonyms. Or rotating the tiles you use in a 2D game. In this case I'd define an interface where you pass in a "seed" integer and it gives you back some deterministic example; a circular array is the simplest implementation of this interface (but there are others).
You could also do simple load balancing by sending work to Worker[workCount++]. While usually you want to track each workers' existing workload (because the work takes unpredictable time), this simple approach could be sufficient if all your work completes in about the same time.
If you're doing fancy math or science computing, you may be working with finite groups or fields, whose elements you could stick in an N-dimensional circular array (based on the characteristics of the field).
Like:
- you can put a short chord sequence into a ring, and it now functions as a list of as many repetitions of that chord sequence as you like. You can just loop over it forever (which is kind of the essence of how sonic pi live-loop play works)
- you can put the notes that make up a scale into a ring, and use it to extract specific chords - like, take the 1st, 3rd, 5th, 7th and 9th note - from just a seven note scale.
- you can use rings of booleans to capture drum patterns and rings of notes to capture melodies, and loop them forever
- etc. etc.