As I got to know there are 256 possible combinations to get for 1 byte. If I understand it correctly, it should mean that you can display any number out of numbers 0-255 and this very number would use only 1 byte of your storage on your computer. Displaying a number out of the numbers from 256 to 65535 would however cost you 2 bytes of your storage (if I understand it the right way). However after typing in the number 65535 into a text document and looking up its file size (the "information" about the text doc) I got to see that the used storage for this document was actually "5 bytes". Does anyone know what the reason for this could be?
-
2Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking.– Community BotCommented Aug 30, 2021 at 0:57
-
9It helps if you understand that 256 possible combinations mean that you can encode (represent) 256 different things in one byte (one at a time). It could be numbers from 0 to 255, or numbers -128 to 127, or characters A, B, C, D, ... a, b, c, d, ... and the rest of the ASCII code, etc. Bytes by themselves don't mean anything, you have to interpret them in some way. Your text document doesn't store the conceptual number 65535, it stores a sequence of individual digits, like letters in a word. It's the number 65535 to you, but to the text editor its just a sequence of character codes.– Filip MilovanovićCommented Aug 30, 2021 at 2:19
-
8You did not save the number 65535 in the file. You saved the numbers 54 followed by 53 and 53 and then 51 followed by 53. These are five one byte numbers (since each character is a byte)– slebetmanCommented Aug 30, 2021 at 8:58
-
1Closed as blatantly off-topic as this is not a software engineering question, it's a "how do computers work" question. Maybe a better SE would be superuser.com?– BlueRaja - Danny PflughoeftCommented Aug 30, 2021 at 22:28
-
1@BlueRaja-DannyPflughoeft. This is not about "how computers work", it is about "how software works" and thus perfectly fine. The question is also perfectly clear. The reason given for closure is just lazy and borders vandalism.– Martin MaatCommented Aug 31, 2021 at 7:10
7 Answers
TL;DR
The key takeaway here is that there is a world of difference between the number 65535 and a piece of text which represents the digits '6', '5', '5', '3' and '5'. It may look the same to you when rendered on a computer screen, but to a computer internally, they are completely unrelated to one another.
The rest of this answer is a lengthy elaboration on what that means and how it is used in everyday computing.
Data has a type. For example, this answer is a text type, known to developers as a string
. A number is a different type. There are several number types, based on what it is you're storing (int
for integers, uint
for positive integers, long
for bigger integers, float
or double
for decimal values, ...).
Why do data types matter? Well, it's sort of similar to why we have file extensions.
Based on the file extension, the file data gets read in a different way. You can easily test this by taking an .mp3 file, changing its extension to .txt, and opening it. You'll see that your OS opens your text editor, not your media player, because it bases its choice on the file extension of the file you're trying to open.
In that text editor, you'll see characters. It's not readable, but as far as your text editor is concerned, this is all valid. You can remove some characters, add some more, and save the file.
If you now change the extension back to .mp3 and play it, you'll notice that the file is damaged. Maybe it's totally broken, maybe it only has a small glitch in it; this depends on what you changed and how you changed it.
Cool trick:
Take a Microsoft Office file (.docx or .xlsx, not the older versions), change its file extension to .zip, and open it. Lo and behold, this is a perfectly working zip archive! Since the advent of the .docx (instead of .doc) and .xlsx (instead of .xls) filetypes, Office has really been storing all of its data using ZIP archiving methods.
Any file is really just a long sequence of binary digits. And how we interpret those digits is at our discretion. ASCII text encoding is one of these interpretations. It uses a character library of 256 characters, which means that it can get away with using a number (0-255) to denote a single character, and this number handily fits into the space of a single byte. So when a text file is opened, the text editor takes the file data, takes the data one byte at a time, interprets that byte as a number (which inherently ranges from 0-255, and then shows the character for that number.
As an aside, I could write my own file data interpretation. For example, I could use a file's data to generate an image which is 1px tall and is as many pixels wide as the file has bits, and generate a black pixel for every 1
and a red pixel for every 0
in the file data. It's a bit of an odd system, but perfectly viable if I choose to make an application that generates these kinds of images.
Or, alternatively, I could store my students' pass/fail on an exam using a simple stream of bits where 1
is pass and 0
is fail, and I know the order of my students based on some other data I've stored somewhere else (not in this file). This is a highly efficient storage mechanism in terms of data size, but it is also very inflexible in terms of storing additional information (e.g. absentees).
Back to ASCII. You can do this exercise by hand using an ASCII table to look up character values. If your file's first byte is 0100 0001
, which is 65
in decimal, the text editor will give you an A
character.
Following this, you can figure out what 5 letter word I wrote here in ASCII: 0100 0001 0101 0000 0101 0000 0100 1100 0100 0101
. If you take each byte, convert it to a number, and look up what character that is, you'll see that the 5 characters are APPLE
.
One very important thing to notice in that linked ASCII table is that it doesn't just contain letters (a-z and A-Z), it also contains all digits (0-9).
You'll notice that this answer focuses on text, not numbers. There's a clue in your question:
However after typing in the number 65535 into a text document and looking up its file size (the "information" about the text doc) I got to see that the used storage for this document was actually "5 bytes"
The data you entered was parsed as text, not as a number. You did not store the numerical value of 65535
, you stored the individual characters (i.e. text) of 6
, 5
, 5
, 3
, and 5
. Using the ASCII table, this means that your file contains 0011 0110 0011 0101 0011 0101 0011 0011 0011 0101
, which is the same as the APPLE
example, but this time using the characters 65535
.
Here's an online converter so you can play around with this (you can press "Swap" to switch converting to or from binary).
In programming terms, your variable type matters, because it indicates to the compiler how your data should be stored, and how it should be handled.
int myNumber = 65535;
string myString = "65535";
In the first case, it will store your value numerically. 65535 (decimal) is 1111 1111 1111 1111
in binary. However, int
is always 4 bytes, so it gets stored as 0000 0000 0000 0000 1111 1111 1111 1111
. Total size: 4 bytes.
In the second case, it will store each individual text character, which we already know from before is 0011 0110 0011 0101 0011 0101 0011 0011 0011 0101
. Total size: 5 bytes.
Now here's an interesting curve ball:
int myNumberPlusOne = myNumber + 1;
string myStringPlusOne = myString + 1;
In the first case, because you're dealing with a number, the compiler does numerical addition, and stores the sum (65535 + 1 = 65536
) as a new number. myNumberPlusOne
is therefore stored as 0000 0000 0000 0001 0000 0000 0000 0000
, which is a value one bigger than myNumber
. Total size: still 4 bytes.
In the second case, because you're dealing with text, the compiler appends the 1
to the text. Now, you're storing a 6-character string, 655351
, which in binary is 0011 0110 0011 0101 0011 0101 0011 0011 0011 0101 0011 0001
. Total size: 6 bytes.
Here, you can see why data types matter. We store things differently, and we also treat that data differently. Why? Because it makes sense to us that +
on numbers means numerical addition, whereas +
on strings means string concatenation (= appending).
To summarize, the key takeaway here is that there is a world of difference between the number 65535 and a piece of text which represents the digits '6', '5', '5', '3' and '5'. It may look the same to you when rendered on a computer screen, but to a computer internally, they are completely unrelated to one another.
-
To be more precise, ASCII is just one encoding for a specific character set. Nowadays ASCII is used only rarely but it is a subset of UTF8 encoding for Unicode charset.– SulthanCommented Aug 30, 2021 at 12:04
-
4The validity of
string myStringPlusOne = myString + 1;
also depends on what language/compiler you are using. Some compilers will happily implicitly convert that1
to a character-type because you are clearly working with a String type and will assume that's what you meant. Others will give you an error because mixing character-types and numeric-types is not allowed. To reinforce your point: they're different data types.– Seth RCommented Aug 30, 2021 at 14:58 -
9"However, int is always 4 bytes" This is not true, my 16-bit microcontroller begs to differ! Commented Aug 30, 2021 at 16:18
-
2I understand the drive to correct little imperfections in the answer, but this answer is kept simple specifically because it's addressed at a layman. The finer details do not help explain the core focus and edge cases are unnecessarily distracting to get the main message across. I do agree that my explanation is not 100% correct, but the omissions it makes are done to boil the answer down to the topic at hand and keep it as simple as it reasonably can be.– FlaterCommented Aug 30, 2021 at 22:44
-
1Thank you for this amazing and interesting answer @Flater! I appreciate the time you spent on this explanation and am very thankful for it! Commented Sep 1, 2021 at 21:36
There are likely several variables at play here, but 65535 is 5 characters. 1 byte per character = 5 bytes. Text editors don't have a notion of what a number is the same way that your code does, so everything is (at a basic level) stored as a set of characters / a string.
When you write for example, C# code like
int number = 65535;
you're explicitly allocating 4 bytes of memory for that number - even though in this case it could use only 2 bytes. Similarly, you could write
ushort number = 65535;
and then only 2 bytes would be allocated.
But if you write
string number = "65535";
or string otherNumber = "65534";
or string anotherNumber = "95536";
they will all be the same size, and that size has no relation to what the number actually is (with a few exceptions).
When you write things to disk, these can all go out the window, as there are many ways of compressing / optimizing things for storage.
-
3well, the length of a number presented in decimal does put an upper limit on the value of the number, it can't be bigger than 99999. But you could have 00123 or -4567 in addition to some numbers in the tens of thousands.– ilkkachuCommented Aug 30, 2021 at 9:33
-
Strings and plain text files are usually encoded in ASCII or Unicode. One can say quite a lot about the size of those. Their sizes are also much more closely related to what the number actually is than the sizes of integral types, given that the number of bytes required to store it is usually a function of the length of the string, which is a function (log) of the number itself. Integral types, on the other hand, are usually a fixed-size regardless of which number you're actually storing in there (obviously assuming it fits, and a bigger integral type will use more space). Commented Aug 30, 2021 at 12:45
-
@ilkkachu: If you allow
-
as a character, then you could arguably also allow9^9^9
which ups the limit dramatically :-) link "The 9th power of 9 is 387420489 (and I verified the result by hand). No one knows the precise number that is represented by 9 to the 387420489 power , but it begins 428124773….and ends ….89. The complete # will contain 369 x 10^6 digits, will use up 500 miles of paper and take years to read”.– FlaterCommented Aug 30, 2021 at 13:54
As Thomas Weller noted, you can use less than 2 bytes if you restrict the number of possible expressions that you want to convey.
You could even use as little as one bit if you and your communication partner agree that 0 means I had a delicious scrambled egg for breakfast
and 1 means 65535
.
The minimum number of bits required to express some information (in a fixed size number of bits) is the base 2 logarithm of the number of possible expressions, see https://en.wikipedia.org/wiki/Entropy_(information_theory). You can always use less efficient encodings, of course, so 5 bytes is a possible size if you want to express the numbers 0..65535 as decimal ASCII digits, but having 5 bytes also gives you the possibility to communicate START
, END
, Glück
, or {°_°}
. Using 45 bytes you could express I had a delicious scrambled egg for breakfast
and 65535
in a more readable form at the expense of some redundance.
-
If the number is known to be in a given range, you can encode it in a single bit (depending on the range) ;-) Commented Aug 31, 2021 at 20:16
The reason the file contains 5 Bytes of information is because the text (String) '65535'
that you typed in is five characters long.
Each of those characters is very common, a digit, and is part of the infamous character set called ASCII.
Each character in ASCII is exactly 1 Byte long. Thus '65535'
is 5 Bytes long.
Now if you want to represent the integer 65535
just as a number in memory then technically you would only need 2 Bytes yes. Many programming languages do have a data type specifically for that, typically called something like UInt16
or UShort
.
In short, the difference is in storing a number as text (String) vs as an Integer in memory.
-
1If you only want to represent the number 65535, then you need 0 bits, since you are not actually encoding any information. You know that the value is 65535. If you only want to represent the numbers 65535 and 42 then you need 1 bit. Only if you want to represent all the numbers from 0 to 65535, you need 16 bits. Which still doesn't tell you how many bytes you need, because the size of a byte depends on the architecture. Historically, a byte has been 6, 7, 8, 9, 12, and 18 bits, but even today, there are still modern architectures with 1, 12, 16, 24, and 32 bit bytes. Commented Aug 30, 2021 at 13:12
-
2+1 For actually answering the question without delving into number theory etc. Commented Aug 30, 2021 at 14:59
-
Nitpick: ASCII is actually a 7-bit standard, so strictly speaking each ASCII character is not 1 byte long, and for that matter essentially nothing is using true ASCII anymore (in the Western world it’s usually either Unicode or an ISO 8859 derivative, while in East Asia it’s usually one of Unicode, GB 18030, Shift-JIS, or Big5). Commented Aug 30, 2021 at 19:39
-
@AustinHemmelgarn Still each character is 8 Bit long in memory. It would be a little awkward, given common circuitry in your CPU and RAM, to store data that takes up specifically only 7 Bits instead of 8. Commented Jul 6, 2023 at 10:35
A number is a mathematical concept which is not made of bytes. Bits or bytes only come into play when you want to represent (or encode) a number on a computer, and the amount of bits/bytes you need depends on the encoding, which in turn depends on the range of values you want to represent.
If you only ever need to represent a single number, there's no need to encode its value, so the amount of bits necessary is effectively zero.
If you only have a few possible values, you need to enumerate them, and that will cost you
log₂(n)
bits. For instance, if you only ever need 0 and 65535, you can encode either value with one bit.If you need a range of numerical values, which is most useful for maths, you can use one of the standard numerical types. The benefit of using the standard types is that you get all the basic math functions for them for free, implemented either directly by the CPU or by the standard library. The smallest of such standard types on a PC for the C language would be
uint16_t
, which takes two bytes. If you also need negative values, you'll needint32_t
, which takes four bytes.Finally, if you need to be able to represent values besides numbers (e.g.
abc
), you'll have to go for strings. The leanest standard encoding which can represent digits is ASCII, which technically uses 7-bit characters, but most computers will store those in 8-bit bytes anyway, which brings you to 5 bytes, plus if you want to work with strings of different lengths, you need to encode the length of the string. In some formats, the strings are terminated by a zero byte (for a total of 6), in others, the length itself is encoded as a number.
-
1Actually, the smallest unsigned arithmetic type in C is
uint_least8_t
. The smallest that can represent 65535 isuint_least16_t
. Commented Aug 30, 2021 at 17:40 -
1@TobySpeight That is correct in the sense that
uint_least8_t
is required to be present even if an 8 bit type is not available, in which caseuint8_t
won't exist. anduint_least8_t
will be wider than 8 bits.– KazCommented Aug 30, 2021 at 18:48 -
If you only ever need to represent a single number, you could theoretically fit that into effectively 0 bytes, but when/how would that actually be useful? To do anything at all with the number, you'd need to have the number in some conventional numeric data type, which would have a size proportional to the value of the number. This also largely applies to storing a few possible values. The only time I see when one could encode/compress the numbers to those sizes in a useful way would be if you're storing many elements that could only have one of a few values. Commented Aug 31, 2021 at 6:09
-
@BernhardBarker "To do anything at all with the number" implies some sort of arithmetic, right? Arithmetic requires a group to operate on, which means you want to be able to represent other values as well. A few possible values could be used to directly define an arithmetic if they include a zero element, e.g. (
0
= 0,1
= 65535) allows you to do the math with a single bit XOR operation for both+
and-
. Commented Aug 31, 2021 at 7:42 -
"To do anything at all with the number" refers to arithmetic, sure, but also to outputting the number to anywhere (outside of the closed system that knows the mapping of the numbers). If I didn't already know better, I might've read this answer as suggesting, given a 1-bit variable representing 1 of 2 values, you can get the actual number out of it and use it with other variables over different ranges, which is not generally true. In my experience, encoding a number in this way would not be useful in like 99.9%+ of use cases, and most of the other 0.1% is just a compression problem. Commented Aug 31, 2021 at 8:04
TL;DR: With typical representations, it can vary from 2 bytes to 14 bytes.
You ask about the size of 65535 in bytes, and that depends on many factors.
A byte is a unit of 8 bits, that's easy and unambiguous. So, equivalently, we can ask about the size in bits. But what is a bit? That's complicated.
Information theory
In information theory, a bit is a unit of information content, and depends on the probability of a given event.
So, if e.g. the expected numbers can either be 0 or 65535, both occurring with the same probability, you get an information content of 1 bit, and an optimal machine representation occupies 1/8 of a byte.
If you expect any number between 0 and 65535 (with equal probabilities), it's 16 bits, and you can put it into two bytes.
If you expect text with five characters length, using printable US English characters (there are 95 different characters), you get 7737809375 possibilities, implying around 33 bits (if all charaters are equally probably).
Computing
In computing, a bit is a place that can be 0 or 1.
Typical data representations in computers come in two flavors: numbers and text.
Numbers
Data are stored as numbers if it's important to do computations.
Numbers in computers are typically represented using the binary system (base-2), with sizes of 1, 2, 4, or 8 bytes. A further distinction is whether you need negative values ("signed" types) or not ("unsigned").
Then
- 1-byte variables represent numbers between 0 and 255 (unsigned) or -128 to 127 (signed). Your number won't fit here.
- 2-byte variables represent numbers between 0 and 65535 (unsigned) or -32768 to 32767 (signed). Your number will fit into a 2-byte variable only if you can safely ignore negative values.
- 4-byte variables represent numbers between 0 and 4294967296 (unsigned) or -2147483648 and 2147483647. Your number will fit here.
- 8-byte variables represent numbers between 0 and 18446744073709551616 (unsigned) or -9223372036854775808 and 9223372036854775807. Your number will fit here.
So, with number representation, plausible answers for your number are 2 or 4 bytes.
Text
If it's important for you to treat the 65535 as 5 characters that just happen to be decimal digits, you choose a text representation. Then you can
- easily access the individual digits, being 6, 5, 5, 3, and 5,
- distinguish between 00127 and 127 (important if it's a telephone number, but not if you want to do addition or multiplication),
- also have special characters, e.g. 65#35.
Text can be encoded in many ways.
- ASCII encodes each character in one byte (or more exactly: 7 bits, leaving the highest bit zero), but only covers the characters from US English. Then you get 5 bytes for the 5 characters.
- Various other old encodings also use 1 byte per character (ISO-8859 variants, many Windows code pages). Using all 8 bits of the byte allows for some non-English characters.
- Unicode covers "all" characters from "all" scripts all over the world, but needs more than one byte per character. And it comes in various flavors:
- UTF-8 is a variable-length encoding. It uses 1 byte for ASCII characters, and more bytes for others. As 65535 consists only of ASCII characters, you get 5 bytes here.
- UTF-16 uses two bytes per character most of the time. Only some rare foreign characters don't fit in here and need four bytes each. Here your 65535 occupies 10 bytes. Because of the problem of endianness, UTF-16 comes on two flavors (big endian and little endian), and a byte order mark can be prepended to the text for clarification, accounting for additional two bytes.
- A wide-spread convention for text is to add a NUL character to the end, serving as a marker that the text ends here. Depending on the encoding, this can occupy another 1 or 2 bytes.
- If you write to a text file, the most plausible encodings are some ISO-8859 variant (or Windows code page) or UTF-8. Both will result in 5 bytes for your number (byte order marks are typically not used, and end of text is determined by the file system, not needing a special end marker).
What is a byte? Let's assume the modern eight bits.
What is the representation? What other values have to be possible in that representation?
Suppose we assume a pure binary representation which can handle all of the integers from 0 to 65535. In this representation, 65535 is represented by 16 bits: 1111111111111111. This requires two eight-bit bytes.
If the requirement is to have a representation that only handles the two values { 0, 65535 }, or any other choice of two numbers or symbols, we can encode that in as little as one bit: a fraction of a byte.
If we have to represent all integers from -65535 to 65535, using two's complement (or one's complement will need 17 bits, and that will require three bytes.
We can also think about handling the value 65535.0 in the smallest possible floating-point representation we can think of (which still resembles IEEE). The abstract mantissa corresponds to the binary representation and so requires 16 bits, valued 1. However, in floating-point, the leading 1 can be assumed and so it disappears: every nonzero floating-point value is 1.whatever x (base)^exponent
: the 1 is always there, and so we don't have to dedicate a bit to it. Thus the mantissa requires only 15 bits. If we do not allow any exponent in our floating-point representation, only a sign bit, then we are back to 16 bits. But that's a "strawman" floating-point. Genuine floating-point should be able to float the point, so we need an exponent field. Not only that, let's make it a requirement that the exponent must actually encode the exponent value that is required, namely 65535 = 1111111111111111b = 1.111111111111111b x (10b)^1111b, as well as every lower exponent down to zero. Moreover, let's make it a requirement that negative exponents must be handled so we can represent small fractional values closer to zero than 1.0: all exponent values from -16 to +15. That requires a five bit exponent. Thus, in total, we need one bit for the sign, five bits for the exponent and fifteen for the mantissa: 21 bits. That fits into three bytes.
The number 65535 requires five bytes if it is represented as decimal t ext, where each of the digits is actually a digit character. In the USASCII code, which is a subset of Unicode, the digits 0 through 9 are represented by the character codes 48 to 57. In plain old seven bit ASCII formats, or 8 bit encodings such as the various ISO-8859-1 ("ISO Latin-1") encodings, these character codes occupy one byte each.
The character string 65535
could easily require more bytes of storage in memory if the string is made up of a character code point type that is wider than a byte. Other representational issues also arise such as meta-data: character strings have a variable length, and so an indication is required of where they end: a length field or null termination. In the C language, which uses null-terminated strings, the literal object "65535"
claims at least six bytes of storage (on mainstream platforms): five bytes for the content of the string, plus an additional byte whose value is zero, indicating the end of the string. A wide-string literal, L"65535"
, whose elements are of wide character type called wchar_t
, commonly requires twelve bytes (two-byte wchar_t
) or 24 bytes (four-byte, 32-bit wchar_t
). (Some specialized systems that still exist today, such as certain DSP chips, do not have a smallest addressable unit that is 8 bits wide. C compilers for those systems have a char
type that may be 16 or 32 bits or whatever is the applicable unit.)