1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-01-16

はじめに

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

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

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

実行環境

オンラインでコンパイル可能な以下のいずれかで実行確認しました。
Paiza.io
TIO

D言語の場合

  • $e$はE、$π$は、PIという定数定義がstd.mathで用意されている。
  • 複素数は、complexテンプレートが用意されている。
  • べき乗は^^演算子を利用できる。
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);
}
出力結果
-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_EM_PIとして定義されている場合がある。

  • 複素数は、double complexが用意されている。

  • 複素数のべき乗はcpow関数を利用できる。

#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));
}
出力結果
-1.00000000000000000000 0.00000000000000012246
-1.0000000000 0.0000000000

double complex型を複素数形式でそのまま表示できないようです。

C++の場合

  • $e$や$π$は、<cmath>M_EM_PIとして定義。
  • 複素数は、complexテンプレートが用意されている。
  • べき乗はpow関数を利用できる。
#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));
}
出力結果
(-1,1.22465e-16)
-1.0000000000 0.0000000000

C#の場合

  • $e$や$π$は、Math.EMath.PIとして定義。
  • 複素数は、Complexクラスが用意されている。
  • 複素数のべき乗はComplex.Pow関数を利用できる。
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);
  }
}
出力結果
(-1, 1.22464679914735E-16)
-1.0000000000 0.0000000000

Goの場合

  • $e$や$π$は、math.Emath.Piとして定義。
  • 複素数は、complex型が用意されている。
  • 複素数のべき乗はcmplx.Pow関数を利用できる。
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))
}
出力結果
(-1+1.2246467991473515e-16i)
-1.0000000000 0.0000000000

Perlの場合

  • $e$や$π$は、定数定義されていない。
  • 複素数は、1.0 + 1.0 * iといった形で利用できる。
  • べき乗は**演算子を利用できる。
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);
出力結果
-1+1.22464679914735e-16i
-1.0000000000 0.0000000000

Pythonの場合

  • $e$や$π$は、math.emath.piとして定義。
  • 複素数は、complex型が用意されている。
  • べき乗はpow関数を利用できる。
import math
x   = complex(0, math.pi)
ans = pow(math.e, x)
print(ans)
print("%.10f %.10f" % (ans.real, ans.imag))
出力結果
(-1+1.2246467991473532e-16j)
-1.0000000000 0.0000000000

Rubyの場合

  • $e$や$π$は、Math::EMath::PIとして定義。
  • 複素数は、Complex型が用意されている。
  • べき乗は**演算子を利用できる。
x   = Complex(0.0, Math::PI)
ans = Math::E ** x
puts(ans)
printf("%.10f %.10f\n", ans.real, ans.imag)
出力結果
-1.0+0.0i
-1.0000000000 0.0000000000

Rubyでは、演算結果をそのまま出力しても誤差が表示されませんでした。

Haskellの場合

  • $e$は、定数定義されていない。$π$は、piとして定義。
  • 複素数は、1.0 :+ 1.0といった形で利用できる。
  • べき乗は**演算子を利用できる。
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)
出力結果
(-1.0) :+ 1.2246467991473532e-16
-1.0000000000 0.0000000000

Juliaの場合

  • $e$や$π$は、πとして定義。
  • 複素数は、Complex型が用意されている。
    • 虚数単位 im も定数として用意されている。
  • べき乗は^演算子を利用できる。
using Printf
x = π * im  # == complex(0.0, π)
ans =  ^ x
println(ans)
@printf("%.10f %.10f\n", real(ans), imag(ans))
出力結果
-1.0 + 1.2246467991473532e-16im
-1.0000000000 0.0000000000
1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?