less_retarded_wiki/exercises.md
2021-12-31 20:11:00 -06:00

3.4 KiB

Exercises

Here let be listed exercises for the readers of this wiki. You can allow yourself to as many helpers and resources as you find challenging: with each problem you should either find out you know the solution or learn something new while solving it.

  1. What's the difference between free software and open source?
  2. Write a program in C that computes the value of pi without using float/double and any libraries except for stdio.h and stdint.h -- you can only use built-in integer types and those from stdint.h. The program must compute pi as accurately as possible (at least 2 decimals) and write the value out as base 10 decimal.
  3. Say we have an algorithm that finds all pairs of equal numbers in an array of numbers of length N and adds all of these (unordered) pairs to a set S. The algorithm is: for i := 0 to N: for j := 0 to N: if numbers[i] == numbers[j]: add(S,set(i,j)). How can we optimize the algorithm in terms of its execution speed (i.e. make it perform fewer operations)? How did the asymptotic time complexity ("big O") class change?

Solutions

A solution to each problem should be listed here -- keep in mind there may exist other solutions that those listed here.

solution 1:

Both movements share very similar rules of licensing and technically free software and open-source are largely the same. However, free software is fundamentally aiming for the creation ethical software -- that which respects its user's freedom -- while open source is a later movement that tries to adapt free software for the business and abandons the pursuit of ethics.

solution 2:

#include <stdio.h>
#include <stdint.h>

#define DECIMALS 10000

int main(void)
{
  int64_t previousError = 10000000000;
  uint64_t previousPi = 0;

  for (uint64_t gridSize = 2; gridSize < 200000; gridSize *= 2)
  {
    /* We'll sample a grid of points and count those that fall inside the
       circle with radius of gridSize. Thanks to the 8-symmtery of a circle we
       only sample the 1/8th of the plane. */

    uint64_t inCircle = 0;

    for (int y = 0; y < gridSize; ++y)
      for (int x = y; x <= gridSize; ++x)
        if ((x * x + y * y) / gridSize <= gridSize) // if distance is < radius
          inCircle++; // count the point

    // compute pi from the formula for circle area (area = 2 * pi * r):
    uint64_t pi = (inCircle * 8 * DECIMALS) / (gridSize * gridSize);

    int64_t error = pi - previousPi;

    if (error < 0)
      error *= -1;

    if (error > previousError) // error got bigger due to overflows, stop
    {
      puts("that's it");
      break;
    }

    previousError = error;
    previousPi = pi;

    printf("%d.%d\n",pi / DECIMALS,pi % DECIMALS);
  }
}

solution 3:

In the given algorithm we compare all numbers twice. This can be avoided by not comparing a number to previous numbers in the array (because these have already been compared). Additionally we don't have to compare the same number to itself, a number will always be equal to itself:

for i := 0 to N:
  add(S,i,i)     // no need to compare

for i := 0 to N:
  for j := i + 1 to N:
    if numbers[i] == numbers[j]:
      add(S,set(i,j))

While the first algorithm performs N^2 comparisons, the new one only needs N - 1 + N - 2 + N - 3 + ... ~= N * N / 2 = N^2 / 2 comparisons. Even though the new version is always twice as fast, its time complexity class remains the same, that is O(N^2).