Floating Point Data CSCI 125 & 161 / ENGR 144 • Floating point numbers are not exact • Value 0.1 is very close to 1/10, but not Lecture 13 precisely equal to it • 0.1 10 = 0.000110011001100110011... 2 • Cannot rely on accuracy of floating point Martin van Bommel values for With Floating Point Data for With Floating Point Values • Following for loop is syntactically correct • Better to use the for loop for (x = 1.0; x <= 2.0; x += 0.1) ... for (i = 10; i <= 20; i++) ... • On some machines, x will never take on value • Then use the calculation 2.0, but will become 2.00000000000001, x = i / 10.0; which fails the test to give the floating point values for x Equality With Floating Points Approximately Equal • Testing floating point data for equality leads #define Epsilon 0.000001 to problems with precision bool ApproximatelyEqual(double x, double y) • Want to test if equal within some epsilon { • In reality, test if absolute value of difference double diff = abs(x - y); between numbers, divided by the smaller of y = abs(y); their absolute values, is less than ε x = abs(x); if (y < x) x = y; | x y | − return ((diff / x) < Epsilon); < ε min(| x |, | y |) } 1
Numerical Algorithms Successive Approximation • Techniques used by computers to • Steps: implement mathematical functions like sqrt 1. Make a guess at the answer • sqrt function exists in math library 2. Use guess to generate a better answer • Most people just use it 3. If getting closer to actual answer, repeat until guess is close enough • How is it implemented? – Successive approximation? • How to generate next guess? – Series expansion? – need a converging sequence of guesses Newton’s Method Problem with Successive Approx • e.g. • Process will never guarantee an exact answer – Suppose want square root of 16 • Can continue until close enough (?) – Use 8 as first guess - too large, 8 x 8 = 64 • Use ApproximatelyEqual function – Derive next guess by dividing value by guess • Continue until square of guess approx. equal – 16 / 8 = 2, answer must be between 2 and 8 to original number – Use (2 + 8) / 2 = 5 as next guess – 16 / 5 = 3.2, (3.2 + 5) / 2 = 4.1 as next guess – Next guesses: 4.001219512 and 4.00000018584 Newton’s Algorithm Series Expansion double Sqrt(double x) • Value of function approximated by adding { double g = x; terms in a mathematical series if (x == 0) return 0; if (x < 0) • If addition of new term brings total closer to { cout << ”Sqrt on negative number\n”); desired value, series converges and can be return 0; used to approximate result } • Taylor Series Approximation for 0 < x < 2 while (!ApproximatelyEqual(x, g*g)) g = (g + x / g) / 2; 2 3 4 1 1 ( x 1 ) 3 ( x 1 ) 15 ( x 1 ) − − − � x 1 ( x 1 ) ≅ + − − + − + 2 4 2 ! 8 3 ! 16 4 ! return g; } 2
Implement Series Expansion Implementing Taylor Series 2 3 4 1 1 1 1 1 1 ( x 1 ) 3 ( x 1 ) 15 ( x 1 ) − − − • For a series such as: 4 ( 1 � ) � π ≅ − + − + − x 1 ( x 1 ) ≅ + − − + − + 3 5 7 9 2 4 2 ! 8 3 ! 16 4 ! sign 1 xpower Think of each inside term as • Think of each term as coeff factorial odd • Initially • Then, for next term sign = odd = 1; • xpower *= (x-1); • Then, for the next term • factorial *= (i+1); sign = -sign; • coeff *= (0.5-i); odd = odd + 2; Taylor Algorithm Fixing Limitation double TaylorSqrt(double x) { • Taylor Series Approx works for 0 < x < 2 double sum, factorial, coeff, term, xpower; int i; • How can we use it for larger x? factorial = coeff = xpower = term = 1.0; • Recall sum = 0.0; for (i = 0; sum != sum + term; i++) { 4 x 4 x 2 x = = sum += term; coeff *= (0.5 - i); • Then divide by 4 until within range, then xpower *= (x - 1); calcuate sqrt, and multiply by 2’s to recover factorial *= (i + 1); term = coeff * xpower / factorial; • e.g. sqrt(24) = sqrt(4*4*1.5) = 2*2*sqrt(1.5) } return sum; } Taylor Fix double TSqrt(double x) { int mult = 1; if (x == 0) return (0); if (x < 0) { cout << "TSqrt of negative value " << x << endl; return 0; } while (x >= 2){ x /= 4; mult *= 2; } return mult * TaylorSqrt(x); } 3
Recommend
More recommend