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.
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.
c - Size of a float variable and compilation - Stack Overflow
How does a float support bigger numbers than int?
How is the sizeof(float) 4 bytes?
What are the differences between float, int, char, and double in C?
The basic types in C are just there to standardize a single unit of memory (a block of bits) that can be used to store a value. We all know that a computer uses bits as its basic unit of information, however a bit is too small to be useful in and of itself, by defining different types we define different blocks of bits and how to interpret them. When we say "int a", the compiler knows that we are dealing with a basic, signed binary number, and knows the amount of memory it needs to set aside to store that number.
The biggest issue is that the exact size definitions are system dependent and not defined in the specifications.
-
A float and double are both implementations of floating point values in C. floating point numbers are a way to implement decimal and fractional values, of any magnitude in binary and also streamline their arithmetic. It is essentially a binary version of scientific notation. Imagine writing the number 3.14159 In decimal, The mantissa here would be 314159 and the exponent would be -5. You could define a simple function that takes the two numbers (stored in binary) and prints out their combined decimal value, your program could therefore store all decimal numbers as two different numbers in binary, and use its own functions to add them together, print them etc. However, C streamlines this process by giving you a simple container that does all that work for you behind the scene. A floating point standard describes how you would encode the mantissa and exponent into a single binary number. In C, the only difference between a float and a double is the amount of memory set aside to store your number, and thus the greater range and precision of the numbers that you can store. The benefit of this is that you can also describe large integer numbers, for instance, you would need 32 bits to write the number "4 billion" explicitly in binary, but you only need 8 to do the same in floating point (4 x 109). However, you would not be able to write the number 4,123,456,789 as an 8 bit floating point or even a 32 bit floating point number (as you still need to encode the exponent), but it will fit perfectly well in a 32 bit int.
-
A char and int are just basic binary numbers, their only difference being in length (potentially). A character is defined as the smallest unit of data necessary to hold a single text character for that architecture, this is a bit abstractly defined, but for most computer today running x86 platforms, a char is defined as 8 bits (although, on unicode systems it could be 16 bits). An integer is another basic binary number, but it is required to be at least 16 bits long (typically it is either 32 or 64 on modern systems). So a 8 bit char is capable of encoding 256 unique characters, or a number between 0-255 (or a number between -127 and 128) the difference is only in how you interpret the collection of bits. An 32 bit int can store a number between 0 and slightly over 4 billion, or you could half that range and use it to represent a number between (roughly) -2 billion and 2 billion
On some systems, the size of an int may be the same as the size of float, from the memory point of view they are just collections of bits, however the processor will interpret the values differently, and will actually use different circuits to add two numbers together if they are floats vs if they ints.
More on reddit.comExcerpt 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.
Videos
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.
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! :)