#include #include #include #include /*************************************************** * Problem: * * Your manager needs input that is continuous and * varies greatly, yet remains bounded. This is meant * to test a system under stressful input conditions. * * Looking online, you find a collection of functions * called Weierstrass functions. These provide examples * of functions that are continuous everywhere but * differentiable nowhere. * * You summarize one such family here, and next you * would like to implement it. Try this on your own * before looking at the solution below. * * The Weierstrass family of functions considered here * is parameterized by two values 'a' and 'b', where * * 0 < a < 1 * * and * * b = 1, 3, 5, 7, 9, 11, ... * * with the additional requirement * * 3 * ab > 1 + --- pi. * 2 * * The function is * * infinity * ------- * \ k k * W (x) = ) a cos(b pi x). * a,b / * ------- * k = 0 * * Because we cannot calculate infinitely many terms, * we must truncate the series. * * Since * * k k k * |a cos(b pi x)| <= a, * * the absolute value of the omitted tail after k = N * is bounded by * * infinity * ------- N+1 * \ k a * ) a = ---------. * / 1 - a * ------- * k = N+1 * * Therefore, to make the omitted tail less than * 10^-16, it is sufficient to require * * N+1 * a * --------- < 10^-16. * 1 - a * * Solving for N gives * * ln((1 - a)10^-16) * N + 1 > ---------------------. * ln(a) * * Because 0 < a < 1, ln(a) is negative. * * We will additionally require a <= 0.75 so that the * number of terms remains reasonably small. * * Thus, implement this function while including * assertions that * * 1. 0 < a <= 0.75, * 2. b is a positive odd integer, and * 3. ab > 1 + 1.5 pi. * * See: * https://en.wikipedia.org/wiki/Weierstrass_function ***************************************************/ // Function declarations int main(); double weierstrass( double x, double a, int b ); // Function definitions int main() { // Print the output to sixteen significant digits. std::cout.precision( 16 ); for ( int k{ 0 }; k <= 10; ++k ) { double x{ 0.1 + 0.000000001*k }; std::cout << weierstrass( x, 0.6, 11 ) << std::endl; } return 0; } double weierstrass( double x, double a, int b ) { return 0.0; } // To write this function: // // 1. Check that the parameters satisfy the specified // conditions. Use assertions. // // 2. Calculate an appropriate value of N. You have the // formula above in mathematical form, but now you // must translate it into C++. // // Because N must be an integer, use std::ceil() to // determine how many terms are required. // // 3. Calculate // // N // ------- // \ k k // W (x) = ) a cos(b pi x). // a,b / // ------- // k = 0 // // Notes: // // You could calculate each term using // // std::pow( a, k ) // * std::cos( // std::pow( b, k ) // * std::numbers::pi*x // ) // // but consider how much repeated work this performs. // // To calculate // // 0 1 2 N // a, a, a, ..., a // // and // // 0 1 2 N // b, b, b, ..., b, // // you do not need to calculate every power from // scratch. // // Suppose, for example, that you have already // calculated // // 21 // 0.6. // // What is faster when calculating // // 22 // 0.6? // // 1. Multiply the previous value by 0.6, or // // 2. Calculate 0.6^22 from scratch? // // See if you can use this observation to reduce the // amount of work performed by your code. // // The solution is below. // Here is one implementation of the Weierstrass // function defined above. /* double weierstrass( double x, double a, int b ) { assert( (a > 0.0) && (a <= 0.75) ); assert( (b > 0) && (b%2 == 1) ); assert( a*b > 1.0 + 1.5*std::numbers::pi ); // We want the omitted tail to satisfy // // N+1 // a // --------- < 10^-16. // 1 - a // // Thus, it is sufficient to choose N so that // // ln((1 - a)10^-16) // N + 1 > ---------------------. // ln(a) // // Recall that the natural logarithm ln(x) is // implemented by std::log(x). double bound{ std::log( (1.0 - a)*1.0e-16 ) / std::log( a ) }; int N{ static_cast( std::ceil( bound ) ) }; double result{ 0.0 }; double pow_a_k{ 1.0 }; double pow_b_k{ 1.0 }; for ( int k{ 0 }; k < N; ++k ) { result += pow_a_k*std::cos( pow_b_k*std::numbers::pi*x ); pow_a_k *= a; pow_b_k *= b; } return result; } */