CS157 Numbers

- A
*bit*(**b**inary dig**it**) is the fundamental unit of information in the digital realm. - A bit has two values: 0/1, false/true, off/on
- Other units are made up of bits
- Byte — 8 bits
- Kilobyte (kB) — 2
^{10}bytes — 1024 bytes - Megabyte (MB) — 2
^{20}bytes - Gigabyte (GB) — 2
^{30}bytes — 2^{10}MB

- With one bit we can represent two values, 0 or 1.
- With sequences of bits we can represent (exponentially) more values.
- A sequence of n bits can take on 2ⁿ different values.
- For n=3, we have 2³=8 different values:

000 | 100 |

001 | 101 |

010 | 110 |

011 | 111 |

- The binary number system is a way of
representing numbers with a sequence of bits.

d_{n}d_{n-1}… d_{1}d_{0}.d_{-1}d_{-2}… - Each d is a binary digit.
- The value of a number is computed as ∑d
_{n}2ⁿ

- What is the value of 1001001.01 in decimal format?

2^{6}+ 2^{3}+ 2^{0}+ 2^{-2}= 64 + 8 + 1 + ¼ = 73.25 - While binary data is easy for a computer to read, it is a bit tedious for humans.

- Other systems exist for different bases.
- Octal — Base 8, 0–7
- Decimal — Base 10, 0–9
- Hexadecimal — Base 16, 0–9 and A–F (10–15)

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 |

- C allows integer constants to be specified in decimal, octal, and hex.
- Sorry—no binary constants.

- Octal numbers start with
`0`

(zero).`05`

is octal, as if it matters.`010`

is eight!

- Hex numbers start with
`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

- Integers can be represented in a number of different ways in a computer. Given a fixed number of bits to represent the number we are limited in how many integers we can represent.
- If we wish to allow positive and negative numbers, half of the possible values are assigned to positive numbers and half to negative numbers.
- For example, if an integer is represented with 8
bits, we can represent 2
^{8}numbers, ranging from -128 to 127.

- We have seen two basic integer types so far,
`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 |

- The C language standard imposes minimum sizes (see table).
- The sizes must be in order:

sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long) - However, sizes can be the same.

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_{₂} |

- The result was too big for the type we used so we got a value we did not expect.
- This error is known as overflow because the number became too big for the type.
- A similar error can occur if we try to subtract
a number from an
`unsigned int`

with value`0`

.

- C allows us to represent real numbers in floating point format.
Like integer numbers, floating point numbers in C have a fixed range.

d.ddddd×10^{e} - The digits d.ddddd are known as the significand, or mantissa, and the e is the exponent.

- When representing floating point numbers in a
computer we have to decide several things.
- How many bits do we use for the mantissa?
- How many bits do we use for the exponent?
- Should we have special values for ±∞ and NaN?

- One standard format used by most modern computers is the IEEE 754 floating point standard.
- Floating point arithmetic in a computer introduces a number of problems.

- Some numbers, like 0.2, can not be represented exactly in a binary floating point representation.
- Some operations result in values that can not be represented exactly, ⅔ = 0.66667.
- These types of errors are known as rounding errors and can cause computations to produce erroneous results.

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

- Because of these kinds of errors, floating-point arithmetic does not
have certain properties that we might expect.
- associativity: a+(b+c) ≠ (a+b)+c
- distributivity: a·(b+c) ≠ a·b + a·c

- To minimize the effects of these types of errors, we can modify our algorithms and/or use more bits to represent the numbers.

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

- C provides three floating-point types:
`float`

,`double`

, and`long double`

. - The actual number of bytes used for these types will vary with compiler and machine.

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` |

- C requires that all numeric computations be evaluated in double precision.
- So, all floats are converted to double before use in an expression and then converted back to float afterwards.
- The speed of computation with float and
double varies with machine type, but
`double`

is usually the natural, and hence fastest, type.

- Use
`%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). - Using .
*width*in`%f`

(e.g.,`%.3f`

) says how many digits to print after the decimal point. - Using
`%e`

will print the number in exponential notation: 6.022e23 for Avogadro’s Number, 6.022×10^{23}

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`

- Sign
- Exponent
- Mantissa

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 |

- Floating-point numbers (
`float`

,`double`

,`long double`

) are*not*the Platonic ideal numbers that mathematicians use. - They have limited range & precision.

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

- OK, fine, we can’t ask if they’re exactly the same.
- How about if we ask if they’re close enough?

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

Apply to CSU |
Contact CSU |
Disclaimer |
Equal Opportunity

Colorado State University, Fort Collins, CO 80523 USA

© 2018 Colorado State University

Colorado State University, Fort Collins, CO 80523 USA

© 2018 Colorado State University