On Sunday, 24 March 2024 at 22:16:06 UTC, Kdevel wrote:
The term containing the `pow` invocation computes the alternating sequence -1, 1, -1, ..., which can be replaced by e.g.

```d
   immutable int [2] sign = [-1, 1];
   n += sign [i & 1] / (i * 2.0 - 1.0);
```

This saves the expensive call to the pow function.

I also used this code:
```d
import std.stdio : writefln;
import std.datetime.stopwatch;

enum ITERATIONS = 1_000_000;
enum BENCHMARKS = 20;

auto leibniz(bool speed = true)(int iter) {
  double n = 1.0;

  static if(speed) const sign = [-1, 1];

  for(int i = 2; i < iter; i++) {
    static if(speed) {
      const m = i << 1;
      n += sign [i & 1] / (m - 1.0);
    } else {
      n += pow(-1, i - 1) / (i * 2.0 - 1.0);
    }
  }
  return n * 4.0;
}

auto pow(F, G)(F x, G n) @nogc @trusted pure nothrow {
    import std.traits : Unsigned, Unqual;

    real p = 1.0, v = void;
    Unsigned!(Unqual!G) m = n;

    if(n < 0) {
        if(n == -1) return 1 / x;
        m = cast(typeof(m))(0 - n);
        v = p / x;
    } else {
        switch(n) {
          case 0: return 1.0;
          case 1: return x;
          case 2: return x * x;
          default:
        }
        v = x;
    }
    while(true) {
        if(m & 1) p *= v;
        m >>= 1;
        if(!m) break;
        v *= v;
    }
    return p;
}

void main()
{
    double result;
    long total_time = 0;

    for(int i = 0; i < BENCHMARKS; i++)
    {
        auto sw = StopWatch(AutoStart.no);
        sw.start();

        result = ITERATIONS.leibniz;//!false;

        sw.stop();
        total_time += sw.peek.total!"nsecs";
    }

    result.writefln!"%0.21f";
writefln("Avg execution time: %f\n", total_time / BENCHMARKS / 1e9);
}
```

and results:

dmd -run "leibnizTest.d"
3.141594653593692054727
Avg execution time: 0.002005

If I compile with leibniz!false(ITERATIONS) the average execution time increases slightly:

Avg execution time: 0.044435

However, if you pay attention, it is not connected to an external library and a power function that works with integers is used. Normally the following function of the library should be called:

Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @nogc @trusted pure nothrow
if (isFloatingPoint!(F) && isFloatingPoint!(G))
...

Now, the person asking the question will ask why it is slow even though we use exactly the same codes in C; rightly. You may think that the more watermelon you carry in your arms, the slower you naturally become. I think the important thing is not to drop the watermelons :)

SDB@79

Reply via email to