「世界一美しい数式」をプログラムで表現する

# はじめに

$e^{iπ} = -1$
は、「世界一美しい数式」といわれているオイラーの等式です。
確かに美しいというか無駄がないという感じですが、これをプログラムで出力してみたいと思いました。
ただ、それだけです。

とはいえ、一見簡単そうな数式ですが、プログラムで表現するのは少しだけ手間です。

* $e$や$π$といった無理数を扱う必要がある。
* 複素数を扱う必要がある。
* さらに、複素数のべき乗を扱う必要がある。

# 実行環境
オンラインでコンパイル可能な以下のいずれかで実行確認しました。
[Paiza.io](https://paiza.io/ja)
[TIO](https://tio.run)

# D言語の場合

* $e$は`E`、$π$は、`PI`という定数定義が`std.math`で用意されている。
* 複素数は、`complex`テンプレートが用意されている。
* べき乗は`^^`演算子を利用できる。

```d:
import std;

void main()
{
    auto x = complex(cast(real)0.0, PI);
    auto e = complex(E, cast(real)0.0);
    auto ans = e ^^ x;
    writeln(ans);
    writefln("%.10f %.10f", ans.re, ans.im);
}
```

```text:出力結果
-1-5.01656e-20i
-1.0000000000 -0.0000000000
```

`writeln(ans)`ように、演算結果をそのまま出力すると、`-1-5.01656e-20i`と誤差が発生します。
他のプログラミング言語でもそうですが、無理数を浮動小数で扱う以上、このようになります。
ちなみに、D言語の場合、倍精度(`double`)よりも精度が高い`real`型を利用できるので、虚数部の誤差が`5.01656e-20`と、より少なくなっています。
`double`型を利用すると、他のプログラミング言語と同様`-1+1.22465e-16i`となります。

誤差を丸めて表示するために`writefln("%.10f %.10f", ans.re, ans.im)`と小数点以下10桁表示にしました。
その場合、実数部が`-1.0000000000`、虚数部が`-0.0000000000`と表示されました。

以下、他のプログラミング言語の実装例も紹介します。

# C言語の場合
* $e$や$π$は、C言語の標準仕様では定数定義されていない。
コンパイラにより`M_E`や`M_PI`として定義されている場合がある。

* 複素数は、`double complex`が用意されている。
* 複素数のべき乗は`cpow`関数を利用できる。

```C:
#include <stdio.h>
#include <math.h>
#include <complex.h>

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_E
#define M_E 2.71828182845904523536
#endif

int main(void){
	double complex x1, z;
	x1 = M_PI * I;
	z  = cpow(M_E, x1);
	printf("%.20f %.20f\n", creal(z), cimag(z));
	printf("%.10f %.10f\n", creal(z), cimag(z));
}
```

```text:出力結果
-1.00000000000000000000 0.00000000000000012246
-1.0000000000 0.0000000000
```
`double complex`型を複素数形式でそのまま表示できないようです。

# C++の場合
* $e$や$π$は、`<cmath>`で`M_E`や`M_PI`として定義。
* 複素数は、`complex`テンプレートが用意されている。
* べき乗は`pow`関数を利用できる。

```C++:
#include <iostream>
#include <cmath>
#include <complex>
using std::complex;

int main(void){
    auto x1 = complex<double>(0.0, M_PI);
    auto e  = complex<double>(M_E, 0.0);
    auto z  = pow(M_E, x1);
    std::cout << z << std::endl;
    printf("%.10f %.10f\n", real(z), imag(z));
}
```

```text:出力結果
(-1,1.22465e-16)
-1.0000000000 0.0000000000
```

# C#の場合
* $e$や$π$は、`Math.E`や`Math.PI`として定義。
* 複素数は、`Complex`クラスが用意されている。
* 複素数のべき乗は`Complex.Pow`関数を利用できる。

```C#:
using System;
using System.Numerics;

public class Example
{
  public static void Main()
  {
    Complex x = new Complex(0.0, Math.PI);
    Complex ans = Complex.Pow(Math.E, x);
    Console.WriteLine(ans);
    Console.WriteLine("{0:f10} {1:f10}", ans.Real, ans.Imaginary);
  }
}
```

```text:出力結果
(-1, 1.22464679914735E-16)
-1.0000000000 0.0000000000
```

# Goの場合
* $e$や$π$は、`math.E`や`math.Pi`として定義。
* 複素数は、`complex`型が用意されている。
* 複素数のべき乗は`cmplx.Pow`関数を利用できる。

```Go:
package main

import (
  "fmt"
  "math"
  "math/cmplx"
)

func main() {
     x1  := complex(0, math.Pi)
     ans := cmplx.Pow(math.E, x1)
     fmt.Println(ans)
     fmt.Printf("%.10f %.10f", real(ans), imag(ans))
}
```

```text:出力結果
(-1+1.2246467991473515e-16i)
-1.0000000000 0.0000000000
```

# Perlの場合
* $e$や$π$は、定数定義されていない。
* 複素数は、`1.0 + 1.0 * i`といった形で利用できる。
* べき乗は`**`演算子を利用できる。

```Perl:
use Math::Complex;
my $pi  = 3.14159265358979323846;
my $e   = exp(1.0);
my $x   = 0.0 + $pi * i;
my $ans = $e ** $x;
print $ans, "\n";
printf "%.10f %.10f\n", Re($ans), Im($ans);
```

```text:出力結果
-1+1.22464679914735e-16i
-1.0000000000 0.0000000000
```

# Pythonの場合
* $e$や$π$は、`math.e`や`math.pi`として定義。
* 複素数は、`complex`型が用意されている。
* べき乗は`pow`関数を利用できる。

```Python:
import math
x   = complex(0, math.pi)
ans = pow(math.e, x)
print(ans)
print("%.10f %.10f" % (ans.real, ans.imag))
```

```text:出力結果
(-1+1.2246467991473532e-16j)
-1.0000000000 0.0000000000
```

# Rubyの場合
* $e$や$π$は、`Math::E`や`Math::PI`として定義。
* 複素数は、`Complex`型が用意されている。
* べき乗は`**`演算子を利用できる。

```Ruby:
x   = Complex(0.0, Math::PI)
ans = Math::E ** x
puts(ans)
printf("%.10f %.10f\n", ans.real, ans.imag)
```

```text:出力結果
-1.0+0.0i
-1.0000000000 0.0000000000
```
Rubyでは、演算結果をそのまま出力しても誤差が表示されませんでした。

# Haskellの場合
* $e$は、定数定義されていない。$π$は、`pi`として定義。
* 複素数は、`1.0 :+ 1.0`といった形で利用できる。
* べき乗は`**`演算子を利用できる。

```Haskell:
import Data.Complex
import Text.Printf

main = do
  let x   = 0.0 :+ pi
  let e   = exp 1.0
  let ans = e ** x
  let re  = realPart(ans)
  let im  = imagPart(ans)
  print ans
  printf "%.10f %.10f\n" (re::Double) (im::Double)
```

```text:出力結果
(-1.0) :+ 1.2246467991473532e-16
-1.0000000000 0.0000000000
```

# Juliaの場合
* $e$や$π$は、`ℯ`や`π`として定義。
* 複素数は、`Complex`型が用意されている。
    * 虚数単位 `im` も定数として用意されている。
* べき乗は`^`演算子を利用できる。

```Julia:
using Printf
x = π * im  # == complex(0.0, π)
ans = ℯ ^ x
println(ans)
@printf("%.10f %.10f\n",　real(ans), imag(ans))
```

```text:出力結果
-1.0 + 1.2246467991473532e-16im
-1.0000000000 0.0000000000
```