390 likes | 667 Views
Numerical Error. Data Types: Floating Point Numbers (1). Floating-point numbers have a decimal point, and they can also be signed or unsigned. There are three types: float , double , or long double . The differences between these are their supported range and precision.
E N D
Numerical Error The Ohio State University
Data Types: Floating Point Numbers (1) • Floating-point numbers have a decimal point, and they can also be signed or unsigned. • There are three types: float, double, or longdouble. • The differences between these are their supported range and precision. The Ohio State University
Data Types: Floating Point Numbers (2) • To represent a floating point number: • float uses 32 bits (4 bytes) • double uses 64 bits (8 bytes) • long double uses 128 bits (16 bytes) • The tradeoff is storage vs. precision and range • What exactly is the precision and range, and how are floating point numbers represented in binary format? IEEE 754 Standard The Ohio State University
Numerical Error (1) // example of numerical error #include <iostream> using namespace std; int main() { double x(0.7); // initialize x to 0.7 cout << "(0.7-0.6)*10.0 - 1.0 = " << (x-0.6)*10.0 - 1.0 << endl; return 0; } The Ohio State University
… double x(0.7); // initialize x to 0.7 cout << "(0.7-0.6)*10.0 - 1.0 = " << (x-0.6)*10.0 - 1.0 << endl; … > numerical_error1.exe (0.7-0.6)*10.0 - 1.0 = -2.22045e-16 > The Ohio State University
Numerical Error (2) // print 18 significant digits #include <iostream> using namespace std; int main() { double x(0.7); // initialize x to 0.7 cout << "x = " << x << endl; cout.precision(18); // output 18 significant digits cout << "x = " << x << endl; return 0; } The Ohio State University
… double x(0.7); // initialize x to 0.7 cout << "x = " << x << endl; cout.precision(18); // output 18 significant digits cout << "x = " << x << endl; … > numerical_error2.exe x = 0.7 x = 0.699999999999999956 > The Ohio State University
Numerical Error • Computers store floating point numbers in binary (base 2 or as 0’s and 1’s). • There is no way to represent 0.7 precisely in base 2. • There is no way to represent 0.1 precisely in base 2! The Ohio State University
Numerical Error (3) . . . int main() { cout.precision(18); // output 18 significant digits cout << "0.0 = " << 0.0 << endl; cout << "0.1 = " << 0.1 << endl; cout << "0.2 = " << 0.2 << endl; cout << "0.3 = " << 0.3 << endl; cout << "0.4 = " << 0.1 << endl; cout << "0.5 = " << 0.5 << endl; cout << "0.6 = " << 0.6 << endl; cout << "0.7 = " << 0.7 << endl; cout << "0.8 = " << 0.8 << endl; cout << "0.9 = " << 0.9 << endl; cout << "1.0 = " << 1.0 << endl; return 0; } The Ohio State University
… cout.precision(18); // output 18 significant digits cout << "0.0 = " << 0.0 << endl; cout << "0.1 = " << 0.1 << endl; … > numerical_error3.exe 0.0 = 0 0.1 = 0.100000000000000006 0.2 = 0.200000000000000011 0.3 = 0.299999999999999989 0.4 = 0.100000000000000006 0.5 = 0.5 0.6 = 0.599999999999999978 0.7 = 0.699999999999999956 0.8 = 0.800000000000000044 0.9 = 0.900000000000000022 1.0 = 1 > The Ohio State University
Floating Point Accuracy in Conditional Expressions The Ohio State University
Floating Point Accuracy Issue (1) • WARNING: when comparing floating point numbers (of any kind: float, double, long double, …) you cannot use the == operator reliably • This is a computer limitation. Two numbers, which should be equal, may not be stored as precisely equal in the computer. • Remember numerical accuracy: how would 0.1 be represented in binary notation? It is not possible to add negative powers of 2’s to get an exact representation of 0.1 • Instead, we only get a very good approximation but is still NOT exactly equal to 0.1 The Ohio State University
Floating Point Accuracy Issue (2) • Check it out: float x(0.1); double y(0.1); cout << setprecision(20) << x << endl; cout << setprecision(20) << y << endl; • You should also notice how the doubly precise representation for y gives a far better approximation of 0.1 than that of x, which is only represented by single precision! • Regardless of how closely the number is to 0.1, it certainly is not equivalent The Ohio State University
Floating Point Accuracy Issue (3) float x(0.1); double y(0.1); if (x == y) { cout << “x equals y” << endl; } • The above cout statement will never execute because x and y are not equal (they’re VERY close, but not equal), and therefore the if-statement will not succeed!! The Ohio State University
Be Consistent • Always use the same data type for floating point variables. • In C++, floating point expressions default to double. Consider the expression: cout << 4 * 9.34 << endl; • The number 9.34 is not stored in a variable, but it still needs to be stored SOMEWHERE in memory. So what type is it? By default, C++ stores is as a double. • This is why we ONLY use double (and not float or long double) in this course! The Ohio State University
Floating Point Accuracy Issue (3) double x(0.1); double y(0.1); if (x == y) { cout << “x equals y” << endl; } • The above cout statement will execute since x equals y. The Ohio State University
accuracyError.cpp // error caused by lack of accuracy #include <iostream> using namespace std; int main() { double x(0.1); double y(1e-6); // y = 10^(-6) if (x == (1e5*y)) // if (x == 10^5*10^(-6)) { cout << x << " equals 1e5 x " << y << endl; } else { cout << x << " does not equal 1e5 x " << y << endl; } return 0; } The Ohio State University
… double x(0.1); double y(1e-6); // y = 10^(-6) if (x == (1e5*y)) // if (x == 10^5*10^(-6)) { cout << x << " equals 1e5 x " << y << endl; } else { cout << x << " does not equal 1e5 x " << y << endl; } … >accuracyError.exe 0.1 does not equal 1e5 x 1e-06 > The Ohio State University
Floating Point Accuracy Issue (4) • Instead of checking: if (operand1 == operand2) • See if the difference between them is small enough to assume truth: if (abs(operand1 - operand2) < 0.000001) The Ohio State University
Floating Point Accuracy Issue (5) Or, better yet: if (abs(operand1 – operand2) < EPSILON) • where EPSILON is some constant you have previously declared, and • abs() is the absolute value function for floating point numbers available by including the cmath library The Ohio State University
accuracyExample.cpp // approximating numbers near zero #include <iostream> #include <cmath> using namespace std; int main() { double EPSILON(1e-12); double x(0.1); double y(1e-6); // y = 10^(-6) if (abs(x - (1e5*y)) < EPSILON) // if (abs(x-10^5*10^(-6)) < EPSILON) { cout << x << " equals 1e5 x " << y << endl; } else { cout << x << " does not equal 1e5 x " << y << endl; } return 0; } The Ohio State University
double EPSILON (1e-12); double x(0.1); double y(1e-6); // y = 10^(-6) if (abs(x - (1e5*y)) < EPSILON) // if (abs(x-10^5*10^(-6)) < EPSILON) { cout << x << " equals 1e5 x " << y << endl; } else { cout << x << " does not equal 1e5 x " << y << endl; } >accuracyExample.exe 0.1 equals 1e5 x 1e-06 > The Ohio State University
Type Casting The Ohio State University
Type Casting (1) • Review: We saw one form of coercion through assignment: int a, b; double c; c = a * b; • a * b is an integer but the result is converted to a double when assigned to c. • This type of coercion is implicit The Ohio State University
Type Casting (2) • There is another type of coercion, called “type casting”, which allows the programmer to explicitly force a data type onto an expression. • The cast operator is: dataType(expression) The Ohio State University
Type Casting (3) • Example: int x = 5; double y = log(double(x)); • Alternative format (C version): int x = 5; double y = log((double)(x)); The Ohio State University
logError.cpp // example of cmath function log #include <iostream> #include <cmath> using namespace std; int main() { int value(0); cout << "Enter value: "; cin >> value; // log(value) generates a compiler error cout << "At 10% interest, it will take " << log(value)/log(1.1) << " years for a $1 investment to be worth $" << value << "." << endl; return 0; } The Ohio State University
… // log(value) generates a compiler error cout << "At 10% interest, it will take " << log(value)/log(1.1) << " years for a $1 investment to be worth $" << value << "." << endl; … > g++ logError.cpp –o logError.exe Compiling logError.cpp into logError.exe. logError.cpp: In function `int main()': logError.cpp:16: call of overloaded `log(int&)' is ambiguous /usr/include/iso/math_iso.h:52: candidates are: double log(double) /usr/local/include/g++-v3/bits/std_cmath.h:333: long double std::log(long double) /usr/local/include/g++-v3/bits/std_cmath.h:323: float std::log(float) The Ohio State University
logTypeCast.cpp #include <iostream> #include <cmath> using namespace std; int main() { int value(0); cout << "Enter value: "; cin >> value; // type cast value to double cout << "At 10% interest, it will take " << log(double(value))/log(1.1) << " years for a $1 investment to be worth $" << value << "." << endl; return 0; } The Ohio State University
… // type cast value to double cout << "At 10% interest, it will take " << log(double(value))/log(1.1) << " years for a $1 investment to be worth $" << value << "." << endl; … > logExample.exe Enter value: 10 At 10% interest, it will take 24.1589 years for a $1 investment to be worth $10. > The Ohio State University
lower2Upper.cpp ... int main() { int ascii_A(0), ascii_B(0); char a, b; cout << "Enter initials (2 char): "; cin >> a >> b ; cout << "Ascii " << a << ": " << int(a) << endl; cout << "Ascii " << b << ": " << int(b) << endl; ascii_A = int(a)-32; ascii_B = int(b)-32; cout << "Initials: "; cout << char(ascii_A) << char(ascii_B) << endl; return 0; } The Ohio State University
ASCII Code The Ohio State University
… cout << "Ascii " << a << ": " << int(a) << endl; cout << "Ascii " << b << ": " << int(b) << endl; ascii_A = int(a)-32; ascii_B = int(b)-32; cout << "Initials: "; cout << char(ascii_A) << char(ascii_B) << endl; … > lower2Upper.exe Enter initials (2 char): dj Ascii d: 100 Ascii j: 106 Initials: DJ > The Ohio State University