JavaScriptCoding challenges

CategoryAlgorithms

Published20 January, 2023

Last updated21 January, 2023

AuthorKelly

I recently faced a coding challenge where the result had to be a List class that could handle infinite-length lists. As part of the solution, the List class had to have a `PI()`

method that should return a calculation of π. Long story short, I decided to handle infinity with generator functions and used this same concept to implement the `PI()`

method generator.

Here is an overview of the involved methods to calculate π:

```
class List {
constructor(generator, min = 0, max = Infinity) { /* ... */}
// Implementation of other list methods...
get(n) { /* Obtains a value based on the number provided */ }
static arctan(x) { /* Generator for Arctan series */ }
static get PI() { /* Generator for PI calculation */ }
}
```

This is an overview of how the implementation was built, we can appreciate:

- The
`constructor`

method is the one receiving the generator function and storing it for later use. - The
`arctan`

method receives a parameter named`x`

that we will get in detail later on. - The
`PI`

method is of type`get`

, which means we can directly invoke it and reference its values based on the generator function.

Moving forward, we are going to quickly analyze a few steps before the construction of the `arctan(x)`

method.

The formula I used to build the `arctan(x)`

method refers to this concept of `inverse trigonometry functions`

being arctan one of the most important ones. Since arctan has many different uses, I had to focus only on those used for calculating π. For now, keep in mind the following formula:

`const PI = 4 * ( arctan(1/2) + arctan(1/3) );`

This is a Machin-like formula to calculate the approximate value of π, more specifically it is Euler's solution that implements the Taylor series, a representation of the following infinite sum:

Or if we translate it to code:

`0 + x^1/1 - x^3/3 + x^5/5 - x^7/7 + ...Continues infinitely`

So, here is the implementation of the `arctan(x)`

method I ended up with:

```
static arctan(x) {
function* generator() {
let sum = 0;
for(let i = 0; true; i++) {
sum += (Math.pow(-1, i) * Math.pow(x, 2 * i + 1)) / (2 * i);
yield sum;
}
}
return new List(generator);
}
```

For a better understanding, I will explain the formula in two parts:

- Controlling the current sign.
- Implementation of the Taylor series formula.

Since I decided to have a variable that works as a counter (`i`

) I was able to determine the current operation sign between `+`

and `-`

with the following code:

```
Math.pow(-1, i)
// Examples
console.log(Math.pow(-1, 0)); // 1
console.log(Math.pow(-1, 1)); // -1
console.log(Math.pow(-1, 2)); // 1
console.log(Math.pow(-1, 3)); // -1
```

And since the formula uses the inline sum operator `+=`

it automatically determines the sign that should be used in the current iteration.

The representation of the `x^1/1`

in code is the following fragment of code:

`Math.pow(x, 2 * i + 1) / (2 * i);`

And since it is a sum of all those elements, the result is always being saved to the `sum`

variable:

`sum += (Math.pow(-1, i) * Math.pow(x, 2 * i + 1)) / (2 * i);`

With the previous formula already working, implementing the `PI()`

method was simpler because, as mentioned previously, I used Euler's solution to calculate π. (The formula I suggested to keep in mind)

```
static get PI() {
function* generator() {
let counter = 0;
let pi = 0;
yield pi;
// This formula:
const [ arc1_2, arc1_3 ] = [ List.arctan(1 / 2), List.arctan(1 / 3) ];
while(true) {
// PI = 4 * ( arctan(1/2) + arctan(1/3) )
// Getting the length based on current iteration of PI
pi = 4 * (arc1_2.get(counter) + arc1_3.get(counter));
yield pi;
counter++;
}
}
return new List(generator);
}
```

This was the hardest part because test cases were also approximation assertions. But as far as the entire List class implementation was done it can be used as:

```
console.log(List.PI.get(1)); // 3.333333333333333
console.log(List.PI.get(5)); // 3.1417411974336886
console.log(List.PI.get(12)); // 3.1415926497167876
console.log(List.PI.get(100)); // 3.1415926535897922
```

The higher the `x`

value, the more precise the result will be.