// 11 arrays are created here
int foo[10][10];
It doesn't make sense to create pointers for the 10 inner arrays, so the subtraction would presumably happen when referring to each inner array: int *z = foo[x]; // (char *)foo_sub_1 + (sizeof *foo)*x - (sizeof **foo)
foo[x][y]; // (char *)foo_sub_1 + (sizeof *foo)*x - (sizeof **foo) + (sizeof **foo)*y
In any case, this is more work, both for the computer and for the human. It's analogous to trying to figure out "which year of which century is X in?" (2022 is the 22nd year of the 21st century): year(x) = (x - 1)%100 + 1
century(x) = floor((x - 1)/100) + 1
The above formulae work for the 1-based convention, because they do the necessary 1 subtraction/addition in the right places. If we instead counted from 0, things would be a lot simpler (2021 would be year 21 of century 20): year(x) = x%100
century(x) = floor(x/100)
Unfortunately, the Romans started counting years before anyone knew about 0. I think this is basically why we have a convention of counting from 1: 0 simply wasn't discovered until relatively recently in human history. Earlier number systems such as Greek/Roman numerals don't have a way of representing it.or how would you count, say, 3 Apples? or three legionaries?
You have to remove all desks from #20 to #30, how many desks are there?
Oh, it's 11 desks, I see. This is because we used INCLUSIVE indexing, instead of semi-open interval.
If we use semi-open intervals, we don't include the last item, so that we can write
match index {
0..10 => println!("first ten"),
10..20 => println!("next ten"),
_ => println!("something else"),
}
but this forces us to start our intervals at 0, otherwise we would have to write 1..11 which would be awkward`a..(a+n)` is an n-length range, not an (n + 1)-length range (oh look, an "add 1" operation!).
And an empty range is denoted by `a..a`, not `a..(a-1)` (oh look, a "subtract 1" operation!).
Looking at the Swift standard library, end-exclusive ranges seem to be far more commonly used:
~/build/swift$ git grep -e '\.\.< *[a-zA-Z0-9_(]' --and --not -e '^ *//' -- stdlib/\*.swift | wc -l
599
~/build/swift$ git grep -e '\.\.\. *[a-zA-Z0-9_(]' --and --not -e '^ *//' -- stdlib/\*.swift | wc -l
112I don't think it's inherently more natural to start from 1, just conventional. Disregarding history/convention, I think it would be more natural to use the lowest available natural number.
Back in Roman times, the lowest natural number that people were aware of was "1", so obviously they started counting from that number.
Our understanding of and use of mathematics has evolved since then, and accordingly there are fields such as computer science and combinatorics where there are clear advantages to starting from the smallest number (zero). In virtually all other cases, the reason "1" seems more natural is because that's the way it's been done historically.
It seems that when labelling those apples using a 1-based count, the logic is basically: each apple is identified by the number of apples that precede it, plus 1. The reason for the "plus 1" is that that was your starting number, but it could have easily been 2 or 3. If you instead start from 0, you can omit the "plus X" logic, just as I omitted the "+ 1" and "- 1" logic in my year/century formulae when moving from 1-based to 0-based counting.
> It seems that when labeling ... number ... that precede it, plus one.
I don't think so. It's the number that you have counted once you've counted that one.
It was introduced into western mathematics through Fibonacci in the 1200s at the same time that Hindu-Arabic numerals were adopted, which use "0" as a placeholder (compare this to earlier Greek numerals which work similarly to the system we use today but without placeholders and using different sets of symbols for the different places—and of course no way of representing zero).
I agree with you the subtraction instruction is not exorbitant, especially considering malloc is much more expensive and always has been.