In C, an int and float each take up 4 bytes, or 32 bits, in memory. The difference between int and float is not the number of bits they take up in memory, but rather in the way the ALU (Arithmetic Logic Unit) treats each number. An int is treated as the integer represented by its bits using two's complement notation. A float, on the other hand, is encoded (typically in IEEE 754 format) to represent a number in exponential form (e.g. 2.9979245x108 is a number in exponential form with base 2.9979245 and exponent 8). The number of significant digits in the decimal representation of a floating point number is always about the same: 6-9 digits for 32-bit float and 15-17 digits for a 64-bit float (or double). For example, the value 4.2949673x109 is what I get as the decimal representation of the closest 32-bit float to the number 232 , and it has 8 significant digits.
It can be a common misconception that a floating point number somehow represents more information than a fixed-point number, which is not true. While a 32-bit float can represent numbers of greater magnitude than a 32-bit int, it cannot represent all of them with as much precision. In total, this answer derives that a 32-bit float can represent around 4,278,190,081 unique numbers. This other answer contains a nice plot showing how these 32-bit floats are distributed on the real line.
While an int may not be able to represent numbers with as large of a magnitude as a float, it represents each number in its valid range (-232 to 232-1) with the same precision. The largest number it can represent is 2,147,483,647 and has 10 significant digits. And in total, it can represent 232=4,294,967,296 unique numbers, which is more than for the 32-bit float!
floating point - Float and Int Both 4 Bytes? How Come? - Stack Overflow
How is the sizeof(float) 4 bytes?
How many bytes is a float
c# - What is the size in Byte of this kind of float? - Stack Overflow
In C, an int and float each take up 4 bytes, or 32 bits, in memory. The difference between int and float is not the number of bits they take up in memory, but rather in the way the ALU (Arithmetic Logic Unit) treats each number. An int is treated as the integer represented by its bits using two's complement notation. A float, on the other hand, is encoded (typically in IEEE 754 format) to represent a number in exponential form (e.g. 2.9979245x108 is a number in exponential form with base 2.9979245 and exponent 8). The number of significant digits in the decimal representation of a floating point number is always about the same: 6-9 digits for 32-bit float and 15-17 digits for a 64-bit float (or double). For example, the value 4.2949673x109 is what I get as the decimal representation of the closest 32-bit float to the number 232 , and it has 8 significant digits.
It can be a common misconception that a floating point number somehow represents more information than a fixed-point number, which is not true. While a 32-bit float can represent numbers of greater magnitude than a 32-bit int, it cannot represent all of them with as much precision. In total, this answer derives that a 32-bit float can represent around 4,278,190,081 unique numbers. This other answer contains a nice plot showing how these 32-bit floats are distributed on the real line.
While an int may not be able to represent numbers with as large of a magnitude as a float, it represents each number in its valid range (-232 to 232-1) with the same precision. The largest number it can represent is 2,147,483,647 and has 10 significant digits. And in total, it can represent 232=4,294,967,296 unique numbers, which is more than for the 32-bit float!
I just find it highly surprising that something which represents (virtually) the entire real line is of the same size as that of which represents the Integers.
Perhaps this will become less surprising once you realize that there are lots of integers that a 32-bit int can represent exactly, and a 32-bit float can't.
A float can represent fewer distinct numbers than an int, but they're spread over a wider range.
It is also worth noting that the spacing between consecutive floats becomes wider as one moves away from zero, whereas it remains constant for consecutive ints.
1)
Does sizeof(variable) simply get the variable type and return sizeof(type), which in this case would explain the result ?
Except for variable-length arrays, sizeof doesn't evaluate its operand. So yes, all it cares is the type. So sizeof(someFloatNumb) is 4 which is equivalent to sizeof(float). This explains printf("%i\n", sizeof(someFloatNumb));.
2)
[..] But I can still store a 8 bytes real value in a float, and my compiler says nothing about it. Does/Can gcc grow the capacity of a type ? (managing multiple variables behind the curtains to allow us that sort of things)
No. Capacity doesn't grow. You simply misunderstood how floats are represented/stored. sizeof(float) being 4 doesn't mean
it can't store more than 2^32 (assuming 1 byte == 8 bits). See Floating point representation.
What the maximum value of a float can represent is defined by the constant FLT_MAX (see <float.h>). sizeof(someFloatNumb) simply yields how many bytes the object (someFloatNumb) takes up in memory which isn't necessarily equal to the range of values it can represent.
This explains why printf("%f\n", someFloatNumb); prints the value as expected (and there's no automatic "capacity growth").
3)
printf("%i\n", sizeof(281474976710656));
This is slightly more involved. As said before in (1), sizeof only cares about the type here. But the type of 281474976710656 is not necessarily int.
The C standard defines the type of integer constants according to the smallest type that can represent the value. See https://stackoverflow.com/a/42115024/1275169 for an explanation.
On my system 281474976710656 can't be represented in an int and it's stored in a long int which is likely to be case on your system as well. So what you see is essentially equivalent to sizeof(long).
There's no portable way to determine the type of integer constants. But since you are using gcc, you could use a little trick with typeof:
typeof(281474976710656) x;
printf("%s", x); /* deliberately using '%s' to generate warning from gcc. */
generates:
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘long int’ [-Wformat=] printf("%s", x);
P.S: sizeof results a size_t for which the correct format specifier is %zu. So that's what you should be using in your 1st and 3rd printf statements.
This doesn't store "8 bytes" of data, that value gets converted to an integer by the compiler, then converted to a float for assignment:
float someFloatNumb = 0xFFFFFFFFFFFF; // 6 bytes of data
Since float can represent large values, this isn't a big deal, but you will lose a lot of precision if you're only using 32-bit floats. Notice there's a slight but important difference here:
float value = 281474976710656.000000;
int value = 281474976710655;
This is because float becomes an approximation when it runs out of precision.
Capacities don't "grow" for standard C types. You'll have to use a "bignum" library for that.
Excerpt from the C99 standard, normative annex F (The C++-standard does not explicitly mention this annex, though it includes all affected functions without change per reference. Also, the types have to match for compatibility.):
IEC 60559 floating-point arithmetic
F.1 Introduction
1 This annex specifies C language support for the IEC 60559 floating-point standard. The IEC 60559 floating-point standard is specifically Binary floating-point arithmetic for microprocessor systems, second edition (IEC 60559:1989), previously designated IEC 559:1989 and as IEEE Standard for Binary Floating-Point Arithmetic (ANSI/IEEE 754−1985). IEEE Standard for Radix-Independent Floating-Point Arithmetic (ANSI/IEEE 854−1987) generalizes the binary standard to remove dependencies on radix and word length. IEC 60559 generally refers to the floating-point standard, as in IEC 60559 operation, IEC 60559 format, etc. An implementation that defines
__STDC_IEC_559__shall conform to the specifications in this annex.356) Where a binding between the C language and IEC 60559 is indicated, the IEC 60559-specified behavior is adopted by reference, unless stated otherwise. Since negative and positive infinity are representable in IEC 60559 formats, all real numbers lie within the range of representable values.
So, include <math.h> (or in C++ maybe <cmath>), and test for __STDC_IEC_559__.
If the macro is defined, not only are the types better specified (float being 32bits and double being 64bits among others), but also the behavior of builtin operators and standard-functions is more specified.
Lack of the macro does not give any guarantees.
For x86 and x86_64 (amd64), you can rely on the types float and double being IEC-60559-conformant, though functions using them and operations on them might not be.
Does not say anything about the size.
3.9.1.8
There are three floating point types: float, double, and long double. The type double provides at least as much precision as float, and the type long double provides at least as much precision as double. The set of values of the type float is a subset of the set of values of the type double; the set of values of the type double is a subset of the set of values of the type long double. The value representation of floating-point types is implementation-defined. Integral and floating types are collectively called arithmetic types. Specializations of the standard template std::numeric_limits (18.3) shall specify the maximum and minimum values of each arithmetic type for an implementation.
Hi, not sure if this belongs here or in the main python sub, but decided to try here first. Anyways, I'm working on a project where I have a large text file which essentially contains a roughly 22,000x6,000 matrix of decimal values. This file is >2GB in size, however it's all encoded as text so the size of the data should become considerably smaller once I read them in and represent them as floats (they are mostly a single-digit integer part with 14 digit fractional part, along with the decimal point itself, each character of which UTF-8 can represent as a single byte since it's in the ascii range so each value should use 16 bytes if my calculations are correct). I figure that python represents floats as 8-byte double precision values, as the documentation says CPython will use a C double for your platform to represent them. My googling seems to support this assumption. That would mean that my original matrix in the file should be about 16220006000 ~= 2 GB (not including the whitespace separators), and the matrix in memory as floats should be 8220006000 ~= 1 GB, which while not small, should fit comfortably in memory on my laptop. However, this is not the case and I'm getting an out of memory error as a result.
As a result, I did some investigation and did >>> x = 3.14 >>> sys.getsizeof(x) 24 What the hell, how can this be??? What could CPython possibly be doing with 24 bytes? All I can figure is that there's an 8-byte pointer to a 16-byte double (huge!) and getsizeof() is counting both? Note that this is 64-bit CPython running on linux. I tried again on a 32-bit CPython running on windows and the answer I got was 16 bytes, so I figure this means a 4-byte pointer to an 8-byte double? Somewhat frustrated with this result, I tried again, this time using numpy.float16 because these are relatively small values and I don't need all that space anyways. For the linux 64-bit CPython I got 24 bytes again, and on the Windows 32-bit CPython I got 12 bytes. No idea at all what's happening here because if my previous guesses were correct I should have 8 and 4 byte pointers to 2-byte float16s, giving 10 and 6 bytes, respectively. Clearly I'm missing something here. Can anyone explain what's happening to me, and why so much memory is being used to store these values?
Also, I'm aware that my use case is memory intensive and I'm working on refactoring so that I don't need to have everything in memory at once. However, I'm still extremely curious about this behavior as it seems strange to me. Thanks!
Hi!
I've got a question about C, which has popped up in my mind while following CS50's week 2 and looking up for extra info online.
Apparently, float and int take up the same amount of bytes, 4. However, according to this page, has its limit on 2,147,483,647, while float supports numbers as high as 3.4E+38.
I tried the following code on Programiz's compiler:
#include <stdio.h>
int main() {
// Write C code here
int i = 2000000000000000;
printf("Int value: %i \n", i);
float j = 2000000000000000.0;
printf("Float value: %f", j);
return 0;
}Which returned:
Int value: 1233977344 Float value: 1999999973982208.000000
While the integer overflows, as expected, the float returns a relatively precise value (not completely precise, but close to my input).
How is this possible, considering both take up 4 bytes of memory?
Thank you!
EDIT: Thank you all for your answers! :)
Not guaranteed by the C++ standard, but most machines today follows ISO/IEC/IEEE 60559:2011, or the identical IEEE-754 floating point standard. By this standard, the single precision float is 4 bytes.
You can check std::numeric_limits< float >::is_iec559 in <limits> to make sure.
Yes. Of course, it may be wise to throw a static_assert(sizeof(float)==4, "whatever") in there (or a plain old non-static assert, if the former is not supported by your compiler), just to (a) document your assumption, and (b) notify you if by some cruel twist of fate your platform suddenly does not have 4-byte floats.