Floating Point

Created

Floating Point Numbers

There are other types of numbers other than integers:

  • Rational numbers from ratio ≃ fraction like 10/3.
  • Real numbers like π.

Scientific Notation

Binary numbers in scientific notation. The digit to the left of the decimal point is always 1. The normalized form would be: ±1.x×2y\pm 1.x \times 2^y

  • Where x is the fraction and y is the exponent

IEEE 754 floating point standard. They are templates. A way of encoding base 2 scientific notation.

Single precision uses 4 bytes 1 bit for the sign, 8 bits for the exponents, and 23 bits for the fraction.

  • The way the exponent is stored is in a bias form. This means that we add a bias (127) to the exponent value, and it makes it an unsigned integer. For example, 2−62^{-6} --> exponent = −6+127=121-6 + 127 = 121. We do this because it simplifies the hardware that is used to compare exponents.

Steps to encode

Example conversion from decimal into binary.

π=3.14159265\pi = 3.14159265 First, we convert the number before the period: 310=1123_{10} = 11_{2} Second, we convert the fraction .14159265.14159265

  • Decide if its greater or equal to 0.5. Since it is not, the first digit in the fraction would be zero.
  • Double the digit: 0..14159265×2=0.28318530..14159265 \times 2 = 0.2831853. Since it still not ≥0.5\geq 0.5, we generate another 0.
  • We double again to get 0.56637060.5663706 which is ≥0.5\geq 0.5, so we generate a one.
  • The next value would be 0.13274120.1327412

We can do this inifinitely to increase precision. At the end our value is 11.00100100001111110110111.001001000011111101101

Example encoding into single precision representation π=1.1001001000011111101101×21\pi = 1.1001001000011111101101 \times 2^1

Encoding:

  • sign = 0
  • exponent = 10000000 (because we add the bias to our exponent value of 1: 1+127=1281+127 = 128 that way 128−127=1128-127 = 1 <-- our exponent)
  • Fraction: 1001001000011111101101

Note: the leading 1 in the fraction is ommitted.

C Representation

#include <stdio.h>
int main(void) {
	float x;
	scanf("%f", &x);
	unsigned *p = (unsigned *) &x;
	for (int i = 31; i >= 0; i--) {
		printf("%c", (*p & (1 << i)) ? '1' : '0');
		if (i == 31 || i == 23) { printf(" "); }
	}
	printf("\n");
return 0; 
}

Running the program

$ gcc explain.c  
$ echo '-18.8203125' | ./a.out  

Output

1 10000011 00101101001000000000000

Special cases

  • Zero
  • Infinity (1/0)
  • Negative infinity (-1/0)
  • Not a number (NaN) (0/0 or ∞−∞\infty - \infty )

Encodings

  • Exponent = 0, Fraction = 0, Object = Zero Say you have a region of memory that is filled with zero bits. If you use any of that region to initialize a floating point value, it would represent zero. Which is very nice

  • Exponent = 0, Fraction = >0, Object = Denormalized number Allows more precise representations of values that are very close to zero. Something like 0.x×2−1260.x \times 2^{-126}

  • Exponent = 1-254, Fraction = anything, Object = Normalized number (Floating point number) Allows more precise representations of values that are very close to zero.

  • Exponent = 255, Fraction = 0, Object = infinity

  • Exponent = 255, Fraction = >0, Object = NaN (not a number)

Precision

Single precision = 4 bytes

  • sign = 1 bit, exponent = 8 bits, fraction = 23 bits

Double precision = 8 bytes

  • sign = 1 bit, exponent = 11 bits, fraction = 52 bits

Addition

Flowchart

  1. Start
  2. Compare components: shift smaller number to right until exponents match
  3. Add fractions
  4. Normalize the sum: increase/decrease exponent
  5. Overflow/underflow ? Throw Exception : Move on to step 7
  6. Round fraction to appropriate numeber of bits
  7. Normalized ? Move onto step 8 : Go to step 4
  8. Done

Example We have 4 significant digits in the encoding: .1610+99.99.1610 + 99.99

In scientific notation 1.610×10−1+9.999×1011.610 × 10^{-1} + 9.999 × 10^{1}

Bring the lower number on the same exponent as the higher number, meaning you must round to 4 significant digits 0.016×101+9.999×1010.016 × 10^1 + 9.999 × 10^1

Add the fractions 0.016+9.999=10.0150.016 + 9.999 = 10.015

Adjust exponent 10.015×101=1.0015×10210.015 × 10^1 = 1.0015 × 10^2

Round to 4 significant digits: 1.002×1021.002 × 102

Multiplication

Flowchart

  1. Start
  2. Add exponents
  3. Multiply fractions
  4. Normaize the product: either increase or decrease exponent
  5. Overflow/underflow ? Throw exception : Move onto step 6
  6. Round fraction to appropriate number of bits
  7. Normalized ? Move onto step 8 : Go back to step 4
  8. Set sign
  9. Done