While trying out constexpr I was wondering what else can I get compiler to compute. I can pretty much do any integral computation with both C++ Template Metaprogramming and constexpr, but can I do some floating point computations? It appears I can!!

So I set out to compute `exp(z)`

, using Taylor series implementation for exp:

```
// can't deal with negative powers!!
//
constexpr double pow(double x, int y)
{
return y == 0 ? 1.0 : x * pow(x, y-1);
}
constexpr int factorial(int x)
{
return x == 0 ? 1 : x * factorial(x-1);
}
constexpr double exp(double x)
{
return 1.0 + x + pow(x,2)/factorial(2) + pow(x, 3)/factorial(3)
+ pow(x, 4)/factorial(4) + pow(x, 5)/factorial(5)
+ pow(x,6)/factorial(6) + pow(x, 7)/factorial(7)
+ pow(x, 8)/factorial(8) + pow(x, 9)/factorial(9);
}
int main()
{
constexpr double exp1 = exp(1.0);
return 0;
}
```

In here I have `pow`

function to compute powers of a floating point number, mine is bit limited as it can do integral powers only; `factorial`

straight forward. `exp`

function function goes to `10`

component evaluation. With `exp(1)`

I do see value of `2.7182815255731922`

in debug window while `cout`

prints it to be `2.71828`

. Since this is floating point value I can’t do `static_assert`

.

Now what’s the proof that it was all compile time rather than runtime evaluation, the only way to confirm is to look at what is executed by processor, that’s right assembly:

```
cpp-cxpr`main at main.cpp:388:
0x100000cc0: pushq %rbp
0x100000cc1: movq %rsp, %rbp
0x100000cc4: movl $0x0, %eax
0x100000cc9: movsd 0x247(%rip), %xmm0
0x100000cd1: movl $0x0, -0x4(%rbp)
0x100000cd8: movsd %xmm0, -0x10(%rbp)
0x100000cdd: popq %rbp
0x100000cde: ret
```

Note: there is no instruction for `callq`

, which means no function was called. Since `exp(1.0)`

was evaluated at compile time it’s value was loaded in to register `%xmm0`

at line 5 and then loaded into a local variable (negative offset from `%rbp`

register) at line 7. Life is a bit easy working with debug builds.

Had we not evaluated `exp(z)`

on compile time, just remove constexpr from code in main:

```
double exp1 = exp(1);
// no constexpr - this will be evaluated at runtime
```

generated assembly for main function is:

```
cpp-cxpr`main at main.cpp:388:
0x1000009e0: pushq %rbp
0x1000009e1: movq %rsp, %rbp
0x1000009e4: subq $0x10, %rsp
0x1000009e8: movabsq $0x1, %rax
0x1000009f2: cvtsi2sdq %rax, %xmm0
0x1000009f7: movl $0x0, -0x4(%rbp)
0x1000009fe: callq 0x100000b10 ; exp(double) at main.cpp:354
0x100000a03: movl $0x0, %eax
0x100000a08: movsd %xmm0, -0x10(%rbp)
0x100000a0d: addq $0x10, %rsp
0x100000a11: popq %rbp
0x100000a12: ret
```

Here we are loading abs value 1 into register `%rax`

(line 5), then converting int value to floating point with `cvtsi2sdq`

instruction at line 6 and writing that in `%xmm0`

register. Then at line 8 we are calling `exp(double)`

function which will again put the value in register `%xmm0`

. This value is then moved to a local variable at line 10 (negative offset from `%rbp`

register).

The value computed at runtime is : `2.7182815255731922`

Here is the assembly code generated for `exp(double)`

function:

```
cpp-cxpr`exp(double) at main.cpp:354:
0x100000b10: pushq %rbp
0x100000b11: movq %rsp, %rbp
0x100000b14: subq $0x90, %rsp
0x100000b1b: movl $0x2, %edi
0x100000b20: movabsq $0x1, %rax
0x100000b2a: cvtsi2sdq %rax, %xmm1
0x100000b2f: movsd %xmm0, -0x8(%rbp)
0x100000b34: addsd -0x8(%rbp), %xmm1
0x100000b39: movsd -0x8(%rbp), %xmm0
0x100000b3e: movsd %xmm1, -0x10(%rbp)
0x100000b43: callq 0x100000d20 ; pow(double, int) at main.cpp:344
0x100000b48: movl $0x2, %edi
0x100000b4d: movsd %xmm0, -0x18(%rbp)
0x100000b52: callq 0x100000d90 ; factorial(int) at main.cpp:349
0x100000b57: movl $0x3, %edi
...
...
; many more instructions to make 7 more calls to pow and factorial
...
...
0x100000d17: addq $0x90, %rsp
0x100000d1e: popq %rbp
0x100000d1f: ret
;
; similarly there is code for pow and factorial
;
```

That’s all I have for this post..

Till next time.