#include #include #include /*************************************************** * Problem: * * Having read about the Weierstrass function, you * see a link to another interesting function called * the Blancmange curve: * * https://en.wikipedia.org/wiki/Blancmange_curve * * It is defined by * * infinity * ------- * \ tri(2^k x) * blanc(x) = ) ------------, * / 2^k * ------- * k = 0 * * where tri(x) is the distance from x to the nearest * integer. * * The graph of tri(x) looks like: * * 1/2 | * . . . + . . . . * / \ / \ / \ | / \ / \ / \ / \ * \ / \ / \|/ \ / \ / \ / * ----.-----.-----.-----.-----.-----.---- * -2 -1 0 1 2 3 * | * * In other words, * * tri(x) = min |x - n|, * * where the minimum is taken over all integers n. * * You can read more about this function at: * * https://en.wikipedia.org/wiki/Triangle_wave * * Implement tri(x), and then use it to implement * blanc(x). * * First, suppose you had to implement tri(x) using * only arithmetic, comparisons, and a loop. How * could you find the integer closest to x? * * Next, if you can use std::round(...) and * std::abs(...) from the standard library, * can you find a much simpler implementation? * * To calculate blanc(x), you will need the successive * powers * * 0 1 2 3 * 2, 2, 2, 2, ... * * You could calculate each power using * * std::pow( 2.0, k ), * * but consider how much repeated work this performs. * * If you have already calculated 2^k, what is the * easiest way to calculate 2^(k + 1)? * * Mathematically, the definition requires infinitely * many terms. In double-precision floating-point * arithmetic, however, terms after approximately * k = 53 are generally too small to affect a result * of this magnitude. Thus, for this exercise, sum * the terms for * * k = 0, 1, ..., 53. * * Only the solution is shown below, so do not look * down until you have tried implementing the * functions yourself. ***************************************************/ // Function declarations int main(); double blanc( double x ); double tri( double x ); // Function definitions int main() { // Print the output to sixteen significant digits. std::cout.precision( 16 ); // Correct values: // // 0.0 -> 0 // 0.1 -> 11/30 = 0.366666666... // 0.2 -> 8/15 = 0.533333333... // 0.3 -> 19/30 = 0.633333333... // 0.4 -> 2/3 = 0.666666666... // 0.5 -> 1/2 = 0.5 // 0.6 -> 2/3 = 0.666666666... // 0.7 -> 19/30 = 0.633333333... // 0.8 -> 8/15 = 0.533333333... // 0.9 -> 11/30 = 0.366666666... // 1.0 -> 0 for ( int k{ 0 }; k <= 10; ++k ) { std::cout << blanc( 0.1*k ) << std::endl; } return 0; } double blanc( double x ) { return 0.0; } double tri( double x ) { return 0.0; } // Here is one implementation of the two functions // defined above. /* double blanc( double x ) { assert( (x >= 0.0) && (x <= 1.0) ); double result{ 0.0 }; double two_pow_k{ 1.0 }; for ( int k{ 0 }; k <= 53; ++k ) { result += tri( two_pow_k*x )/two_pow_k; two_pow_k *= 2.0; } return result; } double tri( double x ) { return std::abs( x - std::round( x ) ); } */