CS157 Numbers
000 | 100 |
001 | 101 |
010 | 110 |
011 | 111 |
Base | Number | In Decimal | In Binary |
---|---|---|---|
Binary | 1101100 | 108 | 1 1 0 1 1 0 0 |
Octal | 154 | 108 | 001 101 100 |
Decimal | 108 | 108 | |
Hexadecimal | 6C | 108 | 0110 1100 |
0
(zero).
05
is octal, as if it matters.
010
is eight!
0x
.
// assigning the value 10 in different formats int a = 10, b = 012, c = 0xA; printf("%d %d %d\n", a, b, c);
10 10 10
// We can print numbers in octal and hex using the // formatting strings %o and %x, respectively. printf("%d %o %x\n", 45, 45, 45);
45 55 2d
int
and char
.
C has some modifiers for using different types of integers:
short
— use a representation with less (or equal)
number of bits than the unmodified type
long
— use a representation with more (or equal)
number of bits than the unmodified type
long long
— even more bits
unsigned
— use an unsigned representation 0 to 2ⁿ-1
The full form is short int
, but everybody just writes short
.
It’s like ordering “two salts & a sesame” in a bagel shop.
What does the C language itself require?
Type | Size in bytes |
---|---|
char | 1 |
short | ≥ 2 |
int | ≥ 2 |
long | ≥ 4 |
long long | ≥ 8 |
CSU machines, as of August 2016:
Type | Bytes | Minimum value | Maximum value |
---|---|---|---|
short | 2 | −32,768 | 32,767 |
unsigned short | 2 | 0 | 65,535 |
int | 4 | −2,147,483,648 | 2,147,483,647 |
unsigned | 4 | 0 | 4,294,967,295 |
long | 8 | −9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
unsigned long | 8 | 0 | 18,446,744,073,709,551,615 |
long long | 8 | −9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
unsigned long long | 8 | 0 | 18,446,744,073,709,551,615 |
The signed min & max values are subtly different.
We can use sizeof to see the size of various types on a given machine/compiler. Your sizes may vary!
printf("Size of short int: %zu\n", sizeof(short int)); printf("Size of int: %zu\n", sizeof(int)); printf("Size of long int: %zu\n", sizeof(long int)); printf("Size of char: %zu\n", sizeof(char));
Size of short int: 2 Size of int: 4 Size of long int: 8 Size of char: 1
What happens if we try to store a integer number that’s too big for the given type?
short s = 500; s *= s; printf("The result: %d\n", s);
The result: -12144
500₁₀ | = | 0001 1111 0100₂ |
250000₁₀ | = | 0011 1101 0000 1001 0000₂ |
-12144₁₀ | = | 1101 0000 1001 0000₂ |
unsigned int
with value 0
.
float f = 1.0e9; // one billion f -= 1.0e9; // zero f += 6.0; // six printf("f=%f\n", f); // indeed!
f=6.000000
float f = 1.0e9; // one billion f += 6.0; // one billion and six (we hope) f -= 1.0e9; // six (we hope) printf("f=%f\n", f); // but it’s really zero!
f=0.000000
Adding small numbers to large numbers may result in absorption.
if (1.0e20 + 1 == 1.0e20) puts("equal"); else puts("unequal");
equal
Attempting to represent numbers that are too large results in overflow.
printf("%e\n", 1.0e306 * 1); printf("%e\n", 1.0e306 * 10); printf("%e\n", 1.0e306 * 100); printf("%e\n", 1.0e306 * 1000);
1.000000e+306 1.000000e+307 1.000000e+308 inf
Attempting to represent a number that is too small results in underflow.
printf("%.1e\n", 1.0e-315 / 1.0e0); printf("%.1e\n", 1.0e-315 / 1.0e3); printf("%.1e\n", 1.0e-315 / 1.0e6); printf("%.1e\n", 1.0e-315 / 1.0e9);
1.0e-315 1.0e-318 1.0e-321 0.0e+00
float
, double
, and long double
.
printf("float: %zu\n",sizeof(float)); printf("double: %zu\n",sizeof(double)); printf("long double: %zu\n",sizeof(long double));
On one machine | On a different machine |
---|---|
float: 4 | float: 4 |
double: 8 | double: 8 |
long double: 12 | long double: 16 |
double
is usually the
natural, and hence fastest, type.
%ld
in printf
to print a long int
.
The %f
can be used for double
as well as float
(we learned why on the previous slide).
%f
(e.g., %.3f
) says how many
digits to print after the decimal point.
%e
will print the number in exponential notation:
6.022e23 for Avogadro’s Number, 6.022×1023
printf("%f\n", 12.3456789); printf("%.3f\n", 12.3456789); printf("%.6f\n", 12.3456789); printf("%e\n", 12.3456789); printf("%.2e\n", 12.3456789);
12.345679 12.346 12.345679 1.234568e+01 1.23e+01
Same value, different results.
SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM
Type | Bits | Digits | Bytes | ||
---|---|---|---|---|---|
Sign | Exponent | Mantissa | |||
float | 1 | 8 | 24 | 7.2 | 4 |
double | 1 | 11 | 53 | 15.9 | 8 |
long double (extended) | 1 | 15 | 64 | 19.2 | 12 or 16 |
long double (quad) | 1 | 15 | 113 | 34.0 | 16 |
float
, double
, long double
)
are not the Platonic ideal numbers that mathematicians use.
float f = 1.234e37; printf("f=%g\n", f); printf("f=%g\n", f*10); printf("f=%g\n", f*100); printf("f=%g\n", f*1000);
f=1.234e+37 f=1.234e+38 f=inf f=inf
Sure, double
and long double
have greater range,
but their ranges are finite.
float f = 1.23456789012345678901234567890; printf("f=%.25f\n", f); double d = 1.23456789012345678901234567890; printf("d=%.25lf\n", d); long double l = 1.23456789012345678901234567890L; printf("l=%.25Lf\n", l);
f=1.2345678806304931640625000 d=1.2345678901234566904321355 l=1.2345678901234567889861130
double d = 1.0/49.0; d *= 49.0; printf("%.25f\n", d);
0.9999999999999998889776975
Just because it looks precise in decimal doesn’t mean that the floating-point numbers are precise:
double a=0.1, b=0.2; if (a+b == 0.3) puts("Absolutely equal!"); else printf("The difference is %g\n", a+b - 0.3);
The difference is 5.55112e-17
double a=0.1, b=0.2; double difference = fabs(a+b - 0.3); if (difference < 1e-12) puts("Close enough for engineering"); else puts("Not very close");
Close enough for engineering