#include #include // The 2-norm, or Euclidean length, of a two-dimensional // vector // // / x \ // | | // \ y / // // is // _________ // / 2 2 // \/ x + y . // // Calculating this value directly requires multiplication, // addition and a square root. // // In some applications, particularly those in which speed // is more important than perfect accuracy, we may instead // use an approximation that requires only absolute values, // a comparison, multiplication and addition. // // Define // // 2 cos(pi/8) // a = -------------------------- // 1 + cos(pi/8) // // = 0.96043387010341996525 // // and // // 2 sin(pi/8) // b = -------------------------- // 1 + cos(pi/8) // // = 0.39782473475931601382. // // Now define // // maximum = max(|x|, |y|) // // and // // minimum = min(|x|, |y|). // // The 2-norm can then be approximated by // // a*maximum + b*minimum. // // This is known as the alpha-max-plus-beta-min // approximation. // // With the values of 'a' and 'b' given above, the maximum // relative error is approximately // // 1 - a // // = 0.03956612989658... // // = 3.956612989658...%. // // Thus, the approximation has a maximum relative error // of approximately 3.96%. // // A simpler approximation is // // 0.96*maximum + 0.4*minimum, // // which has a maximum relative error of 4%. The more // precise constants above reduce this maximum error // slightly. // // Relative error: // // If 'approx' is an approximation to an exact nonzero // value 'exact', the relative error is // // |approx - exact| // ------------------. // |exact| // // For example, the relative error when using 3.14 as an // approximation to pi is approximately // // |3.14 - pi| // ----------- = 0.00050696..., // pi // // or approximately 0.0507%. // // Exercise: // // Implement the function // // double fast_norm( double x, double y ); // // so that it returns the alpha-max-plus-beta-min // approximation of the 2-norm of the vector // // / x \ // | |. // \ y / // // Your function must work for all real values of 'x' // and 'y', including negative values. // // To read more about this algorithm, see: // // https://en.wikipedia.org/wiki/Alpha_max_plus_beta_min_algorithm // Function declarations int main(); double fast_norm( double x, double y ); // Function definitions int main() { double x{ 5.3 }; double y{ 0.2 }; double approx{ fast_norm( x, y ) }; double exact{ std::sqrt( x*x + y*y ) }; double rel_error{}; // Relative error is undefined when the exact value // is zero, so handle the zero vector separately. if ( exact == 0.0 ) { rel_error = 0.0; } else { rel_error = std::abs( approx - exact )/exact; } std::cout << "Approximation: " << approx << std::endl; std::cout << "Exact value: " << exact << std::endl; std::cout << "Relative error: " << rel_error << std::endl; std::cout << "Percent relative error: " << (100.0*rel_error) << "%" << std::endl; return 0; } double fast_norm( double x, double y ) { return 0.0; } // Hint: // // Remember that the approximation is // // a*maximum + b*minimum, // // where // // maximum = max(|x|, |y|) // // and // // minimum = min(|x|, |y|). // // Consequently, there are two issues you must consider: // // 1. Either component of the vector may be negative. // // 2. There is no guarantee that 'x' has the larger // absolute value. // // You can solve both issues using conditional statements. // Here is one solution: /* double fast_norm( double x, double y ) { // Define the constants here so that the expressions // using them remain easy to read. double a{ 0.96043387010341996525 }; double b{ 0.39782473475931601382 }; // The approximation depends only on the absolute // values of 'x' and 'y'. Make each value // non-negative. if ( x < 0.0 ) { x = -x; } if ( y < 0.0 ) { y = -y; } // At this point, both 'x' and 'y' are non-negative. // Multiply the larger value by 'a' and the smaller // value by 'b'. if ( x >= y ) { return a*x + b*y; } else { return a*y + b*x; } } */