Skip to content
Snippets Groups Projects
Commit 66d44a64 authored by Sandipan Mohanty's avatar Sandipan Mohanty
Browse files

Add day4 material

parent a9879842
No related branches found
No related tags found
No related merge requests found
Showing
with 5604 additions and 0 deletions
File added
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(cxx2023_d1_examples CXX)
FILE (GLOB sources ./ *.cc)
foreach(source ${sources})
get_filename_component(withoutext "${source}" NAME_WE)
add_executable("${withoutext}" "${source}")
endforeach()
#include <functional>
#include <iostream>
#include <random>
#include <vector>
inline auto power(double x, unsigned N) -> double
{
double ans = 1;
for (unsigned u = 0; u < N; ++u)
ans *= x;
return ans;
}
auto main() -> int
{
std::vector d(1000000, 0.);
double mu{ 1.0 };
double sigma{ 35.8 };
// Fill d with random numbers distributed as a normal
// distribution with mu and sigma as given above.
std::mt19937_64 engine;
std::normal_distribution<> dist{mu, sigma};
auto gen = [&dist, &engine]() mutable {
return dist(engine);
};
for (auto & el : d) el = gen();
// ///////
double mn = 0;
for (auto r : d)
mn += r;
mn /= d.size();
double kn = 0;
for (auto r : d)
kn += power(r - mn, 4);
double kd = 0;
for (auto r : d)
kd += power(r - mn, 2);
std::cout << d.size() * kn / (kd * kd) << "\n";
}
/*
Calculates the date of the last advent in a given
year. Usage:
(i) advent # calculate for current year
(ii) advent 2049 # for 2049
*/
#include <chrono>
#include <cxx20format>
#include <iostream>
auto current_year() -> std::chrono::year
{
using namespace std::chrono;
year_month_day date { floor<days>(system_clock::now()) };
return date.year();
}
auto main(int argc, char* argv[]) -> int
{
using namespace std::chrono;
using namespace std::chrono_literals;
using Date = year_month_day;
using fmt::format;
year Y { argc == 1 ? current_year() : year {std::stoi(argv[1]) }};
Date s4 { Y / December / Sunday[4] };
Date s3 { Y / December / Sunday[3] };
Date xmas { Y / December / 25d };
Date lastadv { s4 >= xmas ? s3 : s4 };
std::cout << format("Last advent for the year {} falls on {}'th of December.\n",
static_cast<int>(Y),
static_cast<unsigned>(lastadv.day()));
}
#include <any>
#include <map>
#include <string>
#include <iostream>
#if __has_include(<boost/core/demangle.hpp>)
#include <boost/core/demangle.hpp>
#define has_boost_demangle 1
#endif
// Uncomment the above to see the type info in a more human readable form
using namespace std;
using namespace std::string_literals;
auto demangle(auto anyobj) -> std::string
{
#ifdef has_boost_demangle
auto dmgnm = boost::core::demangle(anyobj.type().name());
#else
auto dmgnm = anyobj.type().name();
#endif
return "any[[" + dmgnm + "]]";
}
auto main() -> int
{
any var = 1;
cout << "Reading int after storing int ...\n"
<< demangle(var) << ", value = " << any_cast<int>(var) << "\n";
try {
cout << "Trying to get a float after storing an int ... \n";
auto res = any_cast<float>(var);
cout << "extracted value = " << res << "\n";
} catch (const exception& err) {
cout << "Float cast after storing int failed. Error : "
<< err.what() << "\n";
}
var = "Europa"s;
cout << "Reading string after storing string ... \n"
<< demangle(var) << ", value = " << any_cast<string>(var) << "\n";
try {
cout << "Trying to get a int after storing an string ...\n";
auto res = any_cast<int>(var);
cout << "extracted value = " << res << "\n";
} catch (const exception& err) {
cout << "Int cast after storing string failed. Error : "
<< err.what() << "\n";
}
map<string, any> config;
config["max_frequency_ghz"] = 3.3; // any kind of values can be stored
config["memory_MB"] = 16384; // in a container expecting std::any.
config["fingerprint_reader"] = true; // But, you can only read it back
// if you know the type you stored!
}
// In one card game, a deck of cards is shuffled and the first player is given "hand_size" cards.
// Determine the probability distribution of the sum of the numerical values in the cards in the
// hand.
#include <algorithm>
#include <array>
#include <iomanip>
#include <iostream>
#include <random>
constexpr size_t hand_size = 7; // Number of cards in a hand. A compile time constant in this program.
static_assert(hand_size > 0 && hand_size <= 52, "Hand size must be a number between 1 and 52!");
// static_assert can be used as above to ensure we do not violate assumptions made in the code by using
// unsuitable parameters. From now on, we can code assuming that hand_size is a non-zero number no larger
// than 52.
// We are going to need to store the frequencies of the obtained sums in our computer experiment in
// an array, such that H[i] will count how often we ended up with a sum of i. How large does the
// array need to be ? It's a fairly simple calculation, but not a trivial one. We could write a function
// to do it for us. By making the function a "constexpr" function, we can even make it available at
// compile time, so that fixed sized arrays of the right length can be allocated by the compiler,
// based on the results of the evaluation of a non-trivial function.
constexpr auto max_sum(size_t N)
{
// This function calculates the maximum sum of the numbers written on a hand of N cards.
size_t S = 0;
// A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K : 1,2,3,4,5,6,7,8,9,10,11,12,13
size_t largest = 13;
while (N > 4) {
S += 4 * largest; // there are at most 4 of each kind.
largest -= 1; // Equivalent to largest = largest-1
N -= 4;
}
if (N > 0)
S += largest * N;
return S;
}
auto main() -> int
{
std::random_device seed; // Device random number generator, used here only to seed the pseudo-random engine.
std::mt19937 engine{ seed() }; // Mersenne Twister engine, seeded with a call to the device RNG
std::array<int, 52> deck;
std::iota(deck.begin(), deck.end(), 1); // Fills the deck with numbers 1..52
constexpr size_t maxsum = max_sum(hand_size); // hand_size is known at compile time. So, all parameters
// of the constexpr function max_sum are known to the compiler. Hence, it can be evaluated by the
// compiler and the result of the function call can be assigned to a constexpr variable.
// Max sum is the maximum sum obtainable for a hand of cards of size hand_size
std::array<int, maxsum + 1> frequency_of_sum{};
// We can now use a fixed length array to measure frequencies of different results obtained in
// our Monte Carlo experiment.
// We want to store the frequency of a measured sum of S at frequency_of_sum[S].
// But arrays in C, C++ etc. start at index 0, i.e., if A is an array, its elements are
// A[0], A[1], A[2] ... The element A[2] is the third element in an array, A[10] the
// 11'th element. So, if we want frequency_of_sum[364] to be a valid element of the
// array frequency_of_sum, it needs to have at least 365 elements.
constexpr size_t Ntrials = 10'000'000; // Notice how we used the ' sign to group the digits for better
// readability for humans. Use this feature! Stop wasting time staring at things like 1.6666666666,
// and wondering how many 6s there are!
// OK. Time for our Monte Carlo trials...
for (size_t i = 0; i < Ntrials; ++i) {
std::shuffle(deck.begin(), deck.end(), engine);
// shuffle the numbers in the array deck, using "engine" as
// the pseudo-random number source
// Now let's add up the first hand_size numbers
int sum = 0;
if ((i + 1) % 1000000 == 0)
std::cout << "Done with " << i + 1 << " shuffles.\n";
for (size_t j = 0; j < hand_size; ++j) {
auto card = deck[j];
// Here we end up with a number between 1 and 52. 1..13 are hearts,
// 14..26 are spades, 27..39 are clubs and 40..52 are diamonds. But
// we want to only add up the numeric values of the cards, which are
// between 1 and 13. The following line of code does it.
card = (1 + ((card - 1) % 13));
sum += card;
}
frequency_of_sum[sum]++;
}
// Write out the frequency table for the sum obtained in all the trials
std::cout << std::left << std::setw(12) << "Sum"
<< std::left << std::setw(12) << "Frequency"
<< std::left << std::setw(12) << "Probability\n";
for (size_t i = 0; i < frequency_of_sum.size(); ++i) {
std::cout << std::left << std::setw(12) << i
<< std::left << std::setw(12) << frequency_of_sum[i]
<< std::left << std::setw(12) << (1.0 * frequency_of_sum[i]) / Ntrials
<< "\n";
}
}
// examples/chrono_demo.cc
#include <algorithm>
#include <chrono>
#include <cxx20ranges>
#include <iostream>
#include <vector>
constexpr auto is_prime_rec(size_t number, size_t c) -> bool
{
return (c * c > number) ? true : (number % c == 0) ? false
: is_prime_rec(number, c + 1);
}
constexpr auto is_prime(size_t number) -> bool
{
return (number <= 1) ? false : is_prime_rec(number, 2);
}
auto main() -> int
{
using namespace std::chrono;
std::vector<unsigned> primes;
auto t = steady_clock::now();
sr::copy(sv::iota(0UL, 50000UL) | sv::filter(is_prime), back_inserter(primes));
std::cout << "Primes till 50000 are ... " << '\n';
for (unsigned i : primes)
std::cout << i << '\n';
auto d = steady_clock::now() - t;
std::cout << "Prime search took " << duration<double>(d).count() << " seconds\n";
}
#include <iostream>
#include <string>
auto main(int argc, char* argv[]) -> int
{
unsigned long* p = nullptr;
if (argc > 1) {
auto i = std::stoul(argv[1]);
p = &i;
// Since p outlives i, storing address
// of i in p is a bad idea
std::cout << "p is pointing at " << p << " storing a value " << *p << "\n";
} else {
std::cout << "Needs one integer command line argument!\n";
}
// At this point, if argc > 1, p is pointing to
// a location where there was a variable called i
// which has run out of scope. Accessing p here is
// undefined behaviour.
if (p)
std::cout << "p is pointing at " << p << " storing a value " << *p << "\n";
}
#include <vector>
#include <iostream>
auto main() -> int
{
std::vector v{1, 2, 3};
const auto& vstart = v.front();
v.push_back(4);
v.push_back(5);
v.push_back(6);
v.push_back(7);
v.push_back(8);
std::cout << "Start element of v = " << vstart << "\n";
}
#include <iostream>
#include <string>
auto f(double x) -> double&
{
auto y = x * x;
return y;
}
auto main() -> int
{
auto a = 4.0;
auto&& z = f(a);
std::cout << z << "\n";
}
/*
Calculates the years in a given interval, in which
the month of February had 5 Sundays.
Usage:
(i) feb # Start: current year, End: 100 years from now
(ii) feb 1975 # Start: 1975, End: current year
(iii) feb 2075 # Start: current year, End: 2075
(iv) feb 1800 2000 # Start 1800, End 2000
Build:
clang++ -std=c++20 -stdlib=libc++ feb.cc -o feb
*/
#include <chrono>
#include <iostream>
auto current_year() -> std::chrono::year
{
using namespace std::chrono;
year_month_day date { floor<days>(system_clock::now()) };
return date.year();
}
auto main(int argc, char* argv[]) -> int
{
using namespace std::chrono;
using namespace std::chrono_literals;
auto Y0 { current_year() };
auto Y1 = Y0 + years{100};
if (argc > 1) Y1 = year{std::stoi(argv[1])};
if (argc > 2) Y0 = year{std::stoi(argv[2])};
if (Y1 < Y0) std::swap(Y1, Y0);
for (auto y = Y0; y < Y1; ++y) {
auto d = y / February / Sunday[5];
if (d.ok())
std::cout << static_cast<int>(y) << "\n";
}
}
#include <iostream>
#include <map>
#include <random>
auto main() -> int
{
// write code here so that the callable variable
// of name generator gives you a new pseudo-random
// number distributed as a gaussian or
// normal distribution
// auto generator = ?
std::map<int, unsigned> H;
for (unsigned i = 0; i < 5000000; ++i)
H[static_cast<int>(std::floor(generator()))]++;
for (auto& i : H)
std::cout << i.first << " " << i.second << "\n";
}
// examples/opt_qsolve.cc
#include <iostream>
#include <cmath>
#include <optional>
auto solve_quadratic(double a, double b, double c)
-> std::optional<std::pair<double, double>>
{
using namespace std;
optional<pair<double, double>> solution;
auto D = b * b - 4 * a * c;
if (D >= 0) {
auto q = -0.5 * ( b + std::copysign(std::sqrt(D), b) );
solution = make_pair(q / a, c / q );
}
return solution;
}
auto main(int argc, char *argv[]) -> int
{
if (argc < 4) {
std::cerr << "Needs three real numbers as arguments!\n";
return 1;
}
auto c1 = std::stod(argv[1]);
auto c2 = std::stod(argv[2]);
auto c3 = std::stod(argv[3]);
std::cout << "Quadratic equation " << c1 << " x^2 + " << c2 << " x + " << c3 << " = 0 \n";
auto result = solve_quadratic(c1, c2, c3);
// result is an optional pair of doubles
if (result) {
// result evaluated as a condition gives true, which means the optional
// contains a value.
auto [root1, root2] = *result;
// *result unpacks the inner value of the optional
std::cout << "has solutions\n"
<< "x1 = " << root1 << "\n"
<< "x2 = " << root2 << "\n";
} else {
// This block of code is executed if the condition of the if statement
// evaluates to false. In this case, this means the optional
// does not contain a value.
std::cout << "No solution is possible in the space of real numbers.\n";
}
}
#include <iostream>
#include <string>
#include <array>
#include <algorithm>
auto main(int argc, char* argv[]) -> int
{
std::string orig{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"};
auto shuf = orig;
auto n = 5;
do {
std::rotate(shuf.begin(), shuf.begin() + 1, shuf.end());
std::cout << shuf << "\n";
} while (n-- > 0);
}
#include <random>
#include <iostream>
#include <map>
auto main() -> int
{
auto gen = [ dist = std::poisson_distribution<> {8.5}, engine = std::mt19937_64{} ]
() mutable { return dist(engine); };
std::map<int,unsigned> H;
for (auto i = 0UL; i < 5000000UL; ++i) H[gen()]++;
for (auto [i, fi] : H) std::cout << i << " " << fi << '\n';
}
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
// This function prints a given label and then the elements of a container.
// How it works is a topic for a later chapter
template <class Sequence>
void print(Sequence C, std::string label)
{
std::cout << label << "\n";
for (auto element : C)
std::cout << element << ", ";
std::cout << "\n";
}
int main()
{
std::vector<int> v{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
print(v, "Vector v = (after initialization): ");
if (std::is_sorted(v.begin(), v.end()))
std::cout << "The sequence is sorted in the increasing order.\n";
else
std::cout << "The sequence is not sorted in the increasing order.\n";
std::reverse(v.begin(), v.end());
print(v, "After std::reverse: ");
std::rotate(v.begin(), v.begin() + 3, v.end());
print(v, "After std::rotate by 3");
std::sort(v.begin(), v.end());
print(v, "After std::sort");
std::vector<int> w{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, x, y, z;
print(w, "Vector w = ");
std::vector<int> m;
std::merge(v.begin(), v.end(), w.begin(), w.end(), std::back_inserter(m));
print(m, "std::merge of v and w gives ...");
std::set_union(v.begin(), v.end(), w.begin(), w.end(),
std::back_inserter(x));
print(x, "Union of v and w");
std::set_intersection(w.begin(), w.end(), v.begin(), v.end(),
std::back_inserter(y));
print(y, "Intersection of w and v");
std::set_symmetric_difference(v.begin(), v.end(),
w.begin(), w.end(),
std::back_inserter(z));
print(z, "Symmetric difference of v and w");
if (std::is_permutation(z.begin(), z.end(),
v.begin(), v.end())) {
std::cout << "The above sequence is a permutation of the first sequence printed.\n";
} else {
std::cout << "The above sequence is not a permutation of the first sequence printed.\n";
}
}
#include <iostream>
#include <memory>
struct MyStruct {
int vl{ 0 };
MyStruct(int i)
: vl{ i }
{
std::cout << "Creating MyStruct at memory address "
<< (void*)this << " with data " << vl << "\n";
}
~MyStruct()
{
std::cout << "Destroying MyStruct at memory address "
<< (void*)this << " with data " << vl << "\n";
}
MyStruct()
: MyStruct(0)
{
}
};
auto main() -> int
{
auto u1 = std::make_shared<MyStruct>(1);
auto u2 = u1; //ok
auto u3 = std::move(u1);
std::cout << "Data value for u3 is u3->vl = " << u3->vl << "\n";
std::cout << "Reference count of u1 is " << u1.use_count() << "\n";
std::cout << "Reference count of u2 is " << u2.use_count() << "\n";
std::cout << "Reference count of u3 is " << u3.use_count() << "\n";
}
This diff is collapsed.
#include <iostream>
#include <memory>
struct MyStruct {
MyStruct(int i)
: vl{ i }
{
std::cout << "Creating MyStruct at memory address "
<< static_cast<void*>(this) << " with data " << vl << "\n";
}
~MyStruct()
{
std::cout << "Destroying MyStruct at memory address "
<< static_cast<void*>(this) << " with data " << vl << "\n";
}
int vl = 0;
MyStruct()
: MyStruct(0)
{
}
};
auto main() -> int
{
auto u1 = std::make_unique<MyStruct>(1);
// The integer passed as argument is forwarded to the constructor of MyStruct
// auto u2 = u1; //won't compile
auto u3 = std::move(u1);
std::cout << "Data value for u3 is u3->vl = " << u3->vl << "\n";
auto u4 = std::make_unique<MyStruct[]>(4);
// When we want to create an array with make_unique, we have to express
// this wish through the template parameter to make_unique. Here we see
// that u4 becomes an array, even if we are simply passing one integer
// as an argument, like we did for u1.
}
#include <memory>
#include <iostream>
auto main() -> int
{
auto u = std::make_unique<double[]>(1024);
for (auto i = 0UL; i < 1024UL; ++i) u[i] = i;
std::cout << u[334] << "\n";
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment