Byte Ordering: On Holy Wars and a Plea for Peace (1980)
rfc-editor.org
rfc-editor.org
Tip for those with mobile issues: rotate to landscape and the words get bigger ;)
For +90% of web sites I read I only need a "fix font" for the body text and not a full "reader" version of the page.
(That would've been RM; SKB is Stan Kelly-Bootle)
This is because of a mess with where it considered pixels located, where texture samples are considered located, and where, when rasterizing an included pixel, the texture coordinates sampled. See detail at [0].
If your graphics API was blurring all your images, you'd be passionate about that half-pixel offset too.
[0] https://www.gamedev.net/blogs/entry/1848486-understanding-ha...
I understand that it's from Gulliver's Travels where it's about which end to start breaking an egg from - but without knowing this you can easily end up getting this wrong.
The word "End" can also mean any "extremity" and not just the opposite of "beginning". Otherwise phrases "on both ends of the spectrum" wouldn't make sense.
Thus, a positional encoding of a number has one side (end) where the impact of digits is much higher (big) than the other side (end) where the impact is lower (little).
Little end: the side with lower "weight" Big end: the side with higher "weight"
Being "little endian" is a property of the encoding or architecture, not the property of the word. The word is not "little endian", i.e. its "end" is not "little". The encoding is little endian in that it starts with the little end of the word. You're rightly confused because the fact we're now suddenly talking about the start of the word is implicit and based on the assumption that the reader knows Gulliver's tale.
If end means start, then why use this word?
Little endian is in reality little startian and big endian is big startian.
In fact, we could simplify this even further and just call big endian, startian and little endian, just endian.
It's also quite an old terminology which is not going to change.
If we could come up with a new terminology from the start we could find better options.
For example:
* Least/Most Significant First (LSF / MSF) * Low/High Address Least Significant (LALS/HALS)
Etc
u16 x = 1;
u8 * px = (u8 *)&x;
What byte does px point to? LSB orders means that it points to the least significant byte (that has value 1); MSB order means it points to the most significant byte (value 0). int* x; // x is an int-pointer
int *y; // dereferencing y gives an int
int * z; // int multiplied by z
I'm being silly, but floating the the asterisk between the type and the identifier gives me the same feeling as the "array indices start at 0.5" compromise mentioned earlier.(For the record, the second way is the universal and objective truth.)
TLDR: Little endian is better for most data situations (and incidentally is a more natural ordering for humans), so it's good that it won out in the end.
So no, there is no difference in efficiency or performance when it comes to endianness. The only time it would make a difference is if your memory bus width is less than your wordsize and you lack any kind of caching.
To be fair, this is not exactly uncommon for many workloads, even on todays 64bit machines.
That does not sound right, your byte ordering should not affect the ALU, it will always perform the same operations. If you are doing a multi-word add, you have to add from least significant to most significant word because of the carry. And the ALU has no idea what you are adding, whether the numbers are independent or part of a multi-word integer. At best I could imagine that there might be some impact when fetching operands as in big-endian you have to fetch from decreasing addresses which might be less efficient then fetching from increasing addresses.
I do not really understand the "Sorting unknown uint-struct blobs" point.
Could you give an example or explain in more detail, what a "unknown uint-struct blob" is?
The odd/even advantage could be put even stronger, because every additional bit you know from the little end gives additional information about the number's divisibility. For example, one bit tells divisibility by two (aka ofd/even), two bits tell divisibility by four, and so on.
struct someblob {
uint64_t timestamp;
uint64_t checksum;
uint32_t item_count;
struct something items[0];
};
Even if you didn't know that a collection of files were structured this way, you could still read, say, the first 128 bits as an unsigned integer and compare them, and they'd just happen to be naturally ordered because the timestamp field grows from right to left, and would have precedence over the "lower 64 bits" of the checksum field.It's a very minor benefit (of dubious real-world utility), but I wanted to be comprehensive :P
For example, if storing in the keys of a KV store a pattern of:
[u32, String, u32, String, …]
If you want those arrays to be sorted lexicographically, you’ll want to store those u32 instances in big endian, so that both those and the strings sort from left-to-right.
Mentally, I would put this in the "conventional" advantage category, because it relies on comparing fixed length chunks of memory and computationally it should not make a difference if `timestamp` is stored LE or BE for sorting.
BE: t8 t7 t6 t5 t4 t3 t2 t1 c8 c7 c6 c5 c4 c3 c2 c1
In the big endian case, the byte-by-byte of the struct naturally places the timestamp at the high end of the 128 bit value you blindly read. LE: t1 t2 t3 t4 t5 t6 t7 t8 c1 c2 c3 c4 c5 c6 c7 c8
In the little endian case, it's the CHECKSUM at the high end of the 128 bit value.Do you want to:
- Compare just the timestamp, so
1970-01-01 00:00 0x01
1970-01-01 00:00 0x00
1970-01-01 00:00 0x01
1970-01-01 00:01 0x01
1970-01-01 00:01 0x00
1970-01-01 00:01 0x01
could be a valid ordering, with the first three and last three in
arbitrary ordering, because the checksum doesn't play a role.- Compare timestamp and checksum, in the sense of ordering all files with the same checksum by timestamp, like this
1970-01-01 00:00 0x00
1970-01-01 00:01 0x00
1970-01-01 00:02 0x00
1970-01-01 00:00 0x01
1970-01-01 00:01 0x01
1970-01-01 00:02 0x01
- Compare timestamp and checksum, in the sense that files with the same
timestamp are ordered by checksum, in effect grouping equal checksum
files together under their respective date. 1970-01-01 00:00 0x00
1970-01-01 00:00 0x01
1970-01-01 00:00 0x02
1970-01-01 00:01 0x01
1970-01-01 00:01 0x02
1970-01-01 00:01 0x02
1970-01-01 00:01 0x03
In the first case you could just compare the first 64-bit, so I don't
think that's it.
The second case would be an advantage for little-endian, so it doesn't
support your argument.
Third case supports the argument for BE, but is an unusual thing to want.In other words: Is the checksum crucial for your line of argumentation, or could you make your point with just a timestamp? If not, why not compare just 64-bit. If yes, I don't follow why BE is better in this case.
struct myfile {
uint32_t year;
uint8_t month; // Assuming packed structs here
uint8_t day;
uint32_t seconds;
uint16_t my_custom_ordering;
uint8_t some_flags;
uint64_t a_checksum_or_something;
char name[100];
...
}
Reading the first 64 bytes from this file will give year, then month, then day, then seconds, then my_custom_ordering, then some_flags, then a_checksum_or_something, then the first few bytes of name (assuming we used big endian byte ordering). The extra bytes won't hurt anything because they're lower order when we compare.To do this with little endian ordered data, you would have to:
1) Reverse the ordering of the "sortable" fields to: my_custom_ordering, seconds, day, month, year
2) Know in advance that you have to read exactly 12 bytes (no more, no less) from any file using this structure. If you read any more, you'll get random ordering based on the reverse of what's in the "name", "a_checksum_or_something", and "some_flags" fields (because they comprise the "higher order" bytes when reading little endian).
3) If you were to add another field "my_extra_custom_ordering", you'd have to adjust the number of bytes you read. With big endian ordering, you can still read 64 bytes and not care. You'd only care once your "sortable fields" exceeds 64 bytes - at which point you'd read, say, 100 bytes to be completely arbitrary... It doesn't matter because with BE everything just sorts itself out.
The comparator function is also much simpler with BE: Just do a byte-by-byte compare until you find a difference. With LE, you have to start at a specific offset (in the above case, 11) and decrement towards 0.
As long as you deal with fixed length chunks of data accessing it from either end should be equal effort (in first approximation[1]).
This is qualitatively different from the odd/even case, because for a number of unknown length you can tell odd/even in O(1) for LE but need O(n) only for BE (you have to find the LSB in n steps).
Mathematically there is more information you get from just having the LSBs than just having the MSBs without knowing the whole number and its length. I think this the only reason, why LE is marginally better, everything else boils down to convention.
[1] I know that on modern architectures it can be faster to read memory upwards than downwards, because of the pre-fetcher, but this is what I meant with the advantage is because of convention. If we had a symmetric pre-fetcher the point would be moot.
In fact, we can still see the vestiges of the "low order digits first" convention in some languages even today (for example, in German). Even Greek numbers underwent reversals in the early years (earliest known evidence circa 4th century BC).
Also in English, with the numbers thirteen through nineteen (and, fairly well hidden, eleven and twelve)
It was never actually base 12, that would have required inventing 0, But sometimes I wonder if we would not have been better off sticking with base 12.
And before someone chimes in with "base 10 is natural because we have 10 fingers" no we have 8 fingers, by that logic we should be using base 8, but the real winner in using base 12 is count using your finger bones(there are twelve of them) and use your thumb to keep your count, use both hands and you can get to 100(144 in base 10). this is probably why base twelveish was so common, shepards counting sheep. try counting to 100 in base 10 on your fingers, not so natural now is it.
https://www.etymonline.com/search?q=eleven disagrees. It says eleven means “one left” and twelve “two left”, with an implicit “over ten”. That, to me, doesn’t look like base twelve was leading.
80 is "four 20s" (quatrevingt)
92 is "four 20s and 12" (quatrevingt douze)
Not sure where that comes from...
Remember, too, that most people consider every system that they learn first as "natural". Like it's equally true that historically people did not select base 10 very often. Base 12 and base 60 were both popular as well if they're even using positional numbering at all. Nevermind how long we went in positional numbering without a zero. Is zero then unnatural? I think it must be. Is "naturalness" even virtuous then?
My point in the article was that the numbering system was originally little endian because it made things easier when multidigit numbers grow in magnitude in the same direction as you write (least significant digit to the right in this case as it was a right-to-left writing system at the time). This written ordering was then maintained for compatibility reasons in the parts of the world that eventually settled on left-to-right. And the vocalizations ultimately followed those of the dominant cultures of the times - which used left-to-right (with some vestigial exceptions - see my sister comment).
Which no doubt affected the byte order that the early Hindus and Arabs used for their processors. For processors made in the 20th and 21st centuries, however, the numeral order used by people in those centuries is a more relevant data point.
By raw human nature, humans can do it either way. For the humans we have now, with their background, one way is definitely more "natural" than the other. That is, it's more natural to them, because they come with a cultural background.
"three million, one hundred twenty-five thousand, two hundred sixty-nine"
"nine, sixty, two hundred, thousands five, twenty, one hundred, millions three"
It could work either way.
And in fact, in the early days of the Hindu-Arabic numeral system's penetration into Europe, they actually DID lead off with the least significant digit (although numbers larger than thousands were rarely used, and the archaic wordings have only survived in the ones and tens digits - if at all for a particular language).
Yes but one of those ways does not support abbreviation or interruption, or fractions. If you see a 9 digit number for example, you might want to just round off to one or two significant digits while reading it. Having the smallest components first presents obstacles to speech in much the same way Roman numerals do.
The only difference is whether you estimate this number as "about four hundred and forty million" or "about ten and five hundred million"
It comes from Swift's satire about egg eaters. The end in question was the small or large end of the egg and Big Endians broke the big end with the spoon - i.e. it went into the egg cup small end down.
The -ian suffix here is analogous to Christ-ian or Keynes-ian and has nothing to do with "in".