challenge 複素数

以下の計算をしてください。

1. 加算  ( 3 + i ) + ( 4 - i )
2. 減算  ( 5 - 9i ) - ( 2 + 6i )
3. 乗算  ( 5 + 3i )  * ( 5 + 8i )
4. 除算  ( 9 - 7i )  /  ( 9 - 3i )
5. 絶対値  | 2 + 3i |

複素数計算を行う関数やクラスを定義して答えを求めること。
ライブラリがある場合はそれを利用してかまいません。

Posted feedbacks - Flatten

Nested Hidden
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> (+ #C(3 1) #C(4 -1))
7
> (- #C(5 -9) #C(2 6))
#C(3 -15)
> (* #C(5 3) #C(5 8))
#C(1 55)
> (/ #C(9 -7) #C(9 -3))
#C(17/15 -2/5)
> (abs #C(2 3))
3.6055512

Common LispやSchemeだと問題になりませんね、これ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Welcome to MzScheme v4.0 [cgc], Copyright (c) 2004-2008 PLT Scheme Inc.
> (+ 3+i 4-i)
7
> (- 5-9i 2+6i)
3-15i
> (* 5+3i 5+8i)
1+55i
> (/ 9-7i 9-3i)
17/15-2/5i
> (magnitude 2+3i)
3.6055512754639896

クラス定義・演算子定義で。

実行結果:
7.0
3.0 - 15.0i
1.0 + 55.0i
1.1333333333333333 - 0.4i
3.605551275463989
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
object Complex {
  
  implicit def complex2richComplex(c: Complex) = new RichComplex(c)
  class RichComplex(val self: Complex) extends Proxy {
    def abs = self match {
      case Complex(re, im) => Math.sqrt(re*re + im*im)
    }
  }
  
  implicit def int2Complex   (n: Int   ): Complex = Complex(n, 0)
  implicit def double2Complex(n: Double): Complex = Complex(n, 0)
  
  val i = Complex(0, 1)
  
}

case class Complex(real: Double, imag: Double) {
  
  // +(a + bi) = (a + bi)
  def unary_+ = this
  
  // -(a + bi) = (-a - bi)
  def unary_- = Complex(-real, -imag)
  
  // (a + bi) + (c + di) = (a + c) + (b + d)i
  def + (that: Complex) = Complex(this.real + that.real, this.imag + that.imag)
  
  // (a + bi) - (c + di) = (a - c) + (b - d)i
  def - (that: Complex) = Complex(this.real - that.real, this.imag - that.imag)
  
  // (a + bi) * (c + di) = (ac - bd) + (bc + ad)i
  def * (that: Complex) = {
    val Complex(a, b) = this
    val Complex(c, d) = that
    Complex(a*c - b*d, b*c + a*d)
  }
  
  // (a + bi) / (c + di) = (ac + bd) / (c^2 + d^2) + (bc - ad) / (c^2 + d^2)
  def / (that: Complex) = {
    val Complex(a, b) = this
    val Complex(c, d) = that
    val deno = c*c + d*d
    Complex((a*c + b*d) / deno, (b*c - a*d) / deno)
  }
  
  override def toString = this match {
    case Complex(re,  0) => re.toString
    case Complex( 0,  1) => "i"
    case Complex( 0, -1) => "-i"
    case Complex( 0, im) => im.toString + "i"
    case Complex(re,  1) => re.toString + " + i"
    case Complex(re, -1) => re.toString + " - i"
    case Complex(re, im) if im >= 0 => re.toString + " + " + im.toString + "i"
    case Complex(re, im)            => re.toString + " - " + im.abs.toString + "i"
  }
  
}

object Doukaku247 {
  import Complex._
  
  def main(args: Array[String]) {
    
    println( (3 + i  ) + (4 - i  ) )
    println( (5 - 9*i) - (2 + 6*i) )
    println( (5 + 3*i) * (5 + 8*i) )
    println( (9 - 7*i) / (9 - 3*i) )
    println( (2 + 3*i).abs         )
    
  }
  
}

Rでは組み込みです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> ( 3 + 1i ) + ( 4 - 1i )
[1] 7+0i
> ( 5 - 9i ) - ( 2 + 6i )
[1] 3-15i
> ( 5 + 3i ) * ( 5 + 8i )
[1] 1+55i
> ( 9 - 7i )  /  ( 9 - 3i )
[1] 1.133333-0.4i
> abs(2 + 3i)
[1] 3.605551

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
>>> (3 + 1j) + (4 - 1j)
(7+0j)
>>> (5 - 9j) - (2 - 6j)
(3-3j)
>>> (5 + 3j) * (5 + 8j)
(1+55j)
>>> (9 - 7j) / (9 - 3j)
(1.1333333333333333-0.40000000000000002j)
>>> abs(2 + 3j)
3.6055512754639896

Math::Complexをつかってやってみました。
もう少しきれいにかけると思いますが、
とりあえずわかりやすいように上で沢山の変数を宣言してみました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use strict;
use warnings;
use Math::Complex;

my $kasan_a = 3 + i;
my $kasan_b = 4 - i;

my $gensan_a = 5 - 9*i;
my $gensan_b = 2 + 6*i;

my $jyousan_a =  5 + 3*i;
my $jyousan_b = 5 + 8*i;

my $jyosan_a = 9 - 7*i;
my $jyosan_b = 9 - 3*i;

my $zettai = 2 + 3*i;

sub Complex_add{
    my $a = $_[0];
    my $b = $_[1];
    print "$a + $b =",$a+$b,"\n";
}

sub Complex_minus{
    my $a = $_[0];
    my $b = $_[1];
    print "$a - $b =",$a-$b,"\n";
}

sub Complex_times{
    my $a = $_[0];
    my $b = $_[1];
    print "$a * $b =",$a*$b,"\n";
}

sub Complex_divide{
    my $a = $_[0];
    my $b = $_[1];
    print "$a / $b =",$a/$b,"\n";
}

sub Complex_abs{
    my $a = $_[0];
    print "| $a | =",abs($a),"\n";
}
Complex_add($kasan_a,$kasan_b);
Complex_minus($gensan_a,$gensan_b);
Complex_times($jyousan_a,$jyousan_b);
Complex_divide($jyosan_a,$jyosan_b);
Complex_abs($zettai);

Jakarta Commons Math を使ってみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.apache.commons.math.complex.Complex;
import static org.apache.commons.math.complex.ComplexFormat.*;

public class Sample247 {
    public static Complex $(double real, double imaginary) {
        return new Complex(real, imaginary);
    }
    public static void main(String[] args) {
        System.out.println(formatComplex(
                $(3, 1).add($(4, -1))
        ));
        System.out.println(formatComplex(
                $(5, -9).subtract($(2, 6))
        ));
        System.out.println(formatComplex(
                $(5, 3).multiply($(5, 8))
        ));
        System.out.println(formatComplex(
                $(9, -7).divide($(9, -3))
        ));
        System.out.println($(2, 3).abs());
    }
}

深くは考えず、FORTRAN でやってみました☆

 (  7.0000000    ,  0.0000000    )
 (  3.0000000    , -15.000000    )
 (  1.0000000    ,  55.000000    )
 (  1.1333333    ,-0.40000001    )
   3.6055512
1
2
3
4
5
6
print *, ( 3, 1) + ( 4,-1)
print *, ( 5,-9) - ( 2, 6)
print *, ( 5, 3) * ( 5, 8)
print *, ( 9,-7) / ( 9,-3)
print *, abs(( 2, 3))
end

calc(apcalc)で。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ calc '( 3 + 1i ) + ( 4 - 1i )'
    7
$ calc '( 5 - 9i ) - ( 2 + 6i )'
    3-15i
$ calc '( 5 + 3i )  * ( 5 + 8i )'
    1+55i
$ calc '( 9 - 7i )  /  ( 9 - 3i )'
    ~1.13333333333333333333-0.4i
$ calc 'abs( 2 + 3i )'
    3.60555127546398929312

実行結果: (3,1)+(4,-1)=(7,0) (5,-9)-(2,6)=(3,-15) (5,3)*(5,8)=(1,55) (9,-7)/(9,-3)=(1.13333,-0.4) |(2,3)|=3.60555

System Message: WARNING/2 (<string>, line 1); backlink

Inline substitution_reference start-string without end-string.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <complex>
#include <iostream>

using namespace std;

int main(){
    complex<double> dc1(3.0, 1);
    complex<double> dc2(4.0,-1);
    complex<double> dc3(5.0,-9);
    complex<double> dc4(2.0, 6);
    complex<double> dc5(5.0, 3);
    complex<double> dc6(5.0, 8);
    complex<double> dc7(9.0,-7);
    complex<double> dc8(9.0,-3);
    complex<double> dc9(2.0, 3);

    cout << dc1 << '+' << dc2 << '=';
    cout << dc1 + dc2 << "\n";

    cout << dc3 << '-' << dc4 << '=';
    cout << dc3 - dc4 << "\n";

    cout << dc5 << '*' << dc6 << '=';
    cout << dc5 * dc6 << "\n";

    cout << dc7 << '/' << dc8 << '=';
    cout << dc7 / dc8 << "\n";

    cout << '|' << dc9 << "|=";
    cout << abs(dc9) << endl;

}

実行結果をもう一度
(3,1)+(4,-1)=(7,0)
(5,-9)-(2,6)=(3,-15)
(5,3)*(5,8)=(1,55)
(9,-7)/(9,-3)=(1.13333,-0.4)
|(2,3)|=3.60555

J言語では複素数 a + bi を ajb で表現します。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
   3j1 + 4j_1
7
   5j_9 - 2j6
3j_15
   5j3 * 5j8
1j55
   9j_7 % 9j_3
1.13333j_0.4
   | 2j3
3.60555

頑張ってみました。 正直、めんどかったです。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
using System;
class P
{
    static void Main()
    {
        Complex a = new Complex(3, 1);
        Complex b = new Complex(4, -1);
        Complex c = new Complex(5, -9);
        Complex d = new Complex(2, 6);
        Complex e = new Complex(5, 3);
        Complex f = new Complex(5, 8);
        Complex g = new Complex(9, -7);
        Complex h = new Complex(9, -3);
        Complex i = new Complex(2, 3);
        Console.WriteLine("({0}) + ({1}) = {2}", a, b, a + b);
        Console.WriteLine("({0}) - ({1}) = {2}", c, d, c - d);
        Console.WriteLine("({0}) * ({1}) = {2}", e, f, e * f);
        Console.WriteLine("({0}) / ({1}) = {2}", g, h, g / h);
        Console.WriteLine("|{0}| = {1}", i, i.Abs);
    }
}
class Complex
{
    protected double re;
    protected double im;
    protected double abs;
    protected double arg;
    protected static Complex IUnit = new Complex(0, 1);
    public double Re
    {
        set
        {
            this.re = value;
            this.abs = Math.Sqrt(this.re * this.re + this.im * this.im);
            if (this.abs == 0.0)
                this.arg = 0;
            else
                this.arg = Math.Atan2(im, re) * 180 / Math.PI;
        }
        get { return this.re; }
    }
    public double Im
    {
        set
        {
            this.im = value;
            this.abs = Math.Sqrt(this.re * this.re + this.im * this.im);
            if (this.abs == 0.0)
                this.arg = 0;
            else
                this.arg = Math.Atan2(im, re) * 180 / Math.PI;
        }
        get { return this.im; }
    }
    public double Abs
    {
        set
        {
            this.abs = Math.Abs(value);
            this.im = abs * Math.Sin(arg * Math.PI / 180);
            this.re = abs * Math.Cos(arg * Math.PI / 180);
        }
        get { return this.abs; }
    }
    public double Arg
    {
        set
        {
            this.arg = value;
            this.im = abs * Math.Sin(arg * Math.PI / 180);
            this.re = abs * Math.Cos(arg * Math.PI / 180);
        }
        get { return this.arg; }
    }
    public static Complex I
    {
        get { return IUnit; }
    }
    public Complex() : this(0, 0) { }
    public Complex(double a, double b)
    {
        re = a;
        Im = b;
    }
    public string MyToString(int n)
    {
        string str = "";
        double x = Math.Pow(10.0, n);
        double r = Math.Floor(re * x) / x;
        double i = Math.Floor(im * x) / x;
        if (r != 0)
        {
            str += r;
            if (i > 0)
            {
                if (i == 1) str += " + i";
                else str += " + " + i + "i";
            }
            else if (i < 0)
            {
                if (i == -1) str += " - i";
                else str += " - " + (-i) + "i";
            }
        }
        else
        {
            if (i > 0)
            {
                if (i == 1) str += "i";
                else str += i + "i";
            }
            else if (i < 0)
            {
                if (i == -1) str += "-i";
                else str += "-" + (-i) + "i";
            }
        }
        return str;
    }
    public static Complex FromArgAbs(double arg, double abs)
    {
        return new Complex(abs * Math.Cos(arg * Math.PI / 180), abs * Math.Sin(arg * Math.PI / 180));
    }
    public static Complex Sqrt(Complex x)
    {
        return Complex.FromArgAbs(x.arg / 2, Math.Sqrt(x.abs));
    }
    public static Complex PowRatio(Complex x, int num, int den)
    {
        Complex y = x ^ num;
        return Complex.FromArgAbs(y.arg / den, Math.Pow(y.abs, 1.0 / den));
    }
    public static Complex operator -(Complex x)
    {
        return (-1) * x;
    }
    public static Complex operator +(Complex x)
    {
        return x;
    }
    public static Complex operator ~(Complex x)
    {
        return new Complex(x.re, -x.im);
    }
    public static Complex operator ^(Complex x, int n)
    {
        if (n > 0)
        {
            if (n == 1) return x;
            Complex z = 1;
            return (z ^ (n >> 1)) * (z ^ ((n & 1) + (n >> 1)));
        }
        else if (n == 0)
            return 1;
        else
            return (1 / x) ^ (-n);
    }
    public static Complex operator +(Complex x, Complex y)
    {
        return new Complex(x.re + y.re, x.im + y.im);
    }
    public static Complex operator -(Complex x, Complex y)
    {
        return new Complex(x.re - y.re, x.im - y.im);
    }
    public static Complex operator *(Complex x, Complex y)
    {
        return Complex.FromArgAbs(x.arg + y.arg, x.abs * y.abs);
    }
    public static Complex operator /(Complex x, Complex y)
    {
        return Complex.FromArgAbs(x.arg - y.arg, x.abs / y.abs);
    }
    public static bool operator ==(Complex x, Complex y)
    {
        return (x.re == y.re && x.im == y.im);
    }
    public static bool operator !=(Complex x, Complex y)
    {
        return !(x == y);
    }
    public static implicit operator Complex(double x)
    {
        return new Complex(x, 0);
    }
    public static explicit operator Complex(int x)
    {
        return new Complex(x, 0);
    }
    public override bool Equals(object o)
    {
        if (o is Complex)
            return this == (Complex)o;
        else
            return false;
    }
    public override int GetHashCode()
    {
        return (re + im).GetHashCode() ^ (re - im).GetHashCode();
    }
    public override string ToString()
    {
        return MyToString(4);
    }
}

Data.Complexを使いました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import Data.Complex

main = putStrLn $ unlines $ map show
        [
           (3 :+ 1) + (4 :+ (-1))
          ,(5 :+ (-9)) - (2 :+ 6)
          ,(5 :+ 3) * (5 :+ 8)
          ,(9 :+ (-7)) / (4 :+ (-3))
          ,abs (2 :+ 3)
        ]

Cでも、C99から複素数演算が導入されました。こんな風になります。

$ gcc -std=c99 t.c -lm && ./a.out
(3 + 1i) + (4 - 1i) = (7 + 0i)
(5 - 9i) - (2 + 6i) = (3 - 15i)
(5 + 3i) * (5 + 8i) = (1 + 55i)
(9 - 7i) / (9 - 3i) = (1.13333 - 0.4i)
|2 + 3i| = 3.60555

ここでは、FreeBSD 7.1付属gcc 4.2.1を使いました。

記法がアレなのは仕方ありませんが、printf/scanf系書式での対応がないのは残念です。というより面倒です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
$ cat t.c
#include <stdio.h>
#include <complex.h>
#include <math.h>

void print_complex(double complex c)
{
    double i = cimag(c);
    printf("%g %c %gi",
        creal(c),
        i >= 0. ? '+'
                : '-',
        fabs(i));
}

void print_expression(double complex lhs, char ope, double complex rhs, double complex result)
{
    putchar('(');
    print_complex(lhs);
    printf(") %c (", ope);
    print_complex(rhs);
    printf(") = (");
    print_complex(result);
    putchar(')');
    putchar('\n');
}

int main()
{
    double complex al = 3 + I;
    double complex ar = 4 - I;
    double complex sl = 5 - 9 * I;
    double complex sr = 2 + 6 * I;
    double complex pl = 5 + 3 * I;
    double complex pr = 5 + 8 * I;
    double complex dl = 9 - 7 * I;
    double complex dr = 9 - 3 * I;
    double complex bs = 2 + 3 * I;

    double complex a = al + ar;
    double complex s = sl - sr;
    double complex p = pl * pr;
    double complex d = dl / dr;
    double b = cabs(bs);

    print_expression(al, '+', ar, a);
    print_expression(sl, '-', sr, s);
    print_expression(pl, '*', pr, p);
    print_expression(dl, '/', dr, d);
    putchar('|');
    print_complex(bs);
    printf("| = %g\n", b);
}

まさかのExcelです。Excel VBAではありません。いつのバージョンからなのか知りませんが、ワークシート関数として複素数関係のものが揃っています。以下のコードを適当なところに貼り付けてみてください。

Excelでの複素数の扱い方はいたって単純、"1+3i"のような文字列です(虚部のない実数を演算に混ぜることは可能です)。そのままでは、書式指定でも単に文字列として扱われるので、面倒です。

以下余談。Word/Excelでは、今まで自分が欲しいと思った機能が搭載されていなかった試しがありません。さすが最重量級だけのことはあります。というかあんな機能満載では大半の機能は見つけられないし、見つけても使いこなせませんって。

1
2
3
4
5
=IMSUM("3+i", "4-i")
=IMSUB("5-9i", "2+6i")
=IMPRODUCT("5+3i", "5+8i")
=IMDIV("9-7i", "9-3i")
=IMABS("2+3i")

Squeak Smalltalk では複素数は組み込みです。リテラルはなく、整数にメッセージ i を送信することで対応する純虚数値を得るしくみになっています。

1
2
3
4
5
6
( 3 + 1i ) + ( 4 - 1i )   "=> 7 + 0 i "
( 5 - 9i ) - ( 2 + 6i )   "=> 3 - 15 i "
( 5 + 3i ) * ( 5 + 8i )   "=> 1 + 55 i "
( 9 - 7i ) / ( 9 - 3i )   "=> (17/15) - (2/5) i "
( 9.0 - 7.0i ) / ( 9.0 - 3.0i )   "=> 1.133333333333333 - 0.4 i "
( 2 + 3i ) abs            "=> 3.60555127546399 "

D言語で。複素数は組込みなので楽ちん。2.029で動作確認しました。

実行結果:
7+0i
3+-15i
1+55i
1.13333+-0.4i
3.60555
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import std.stdio;
import std.math;        // for abs

void main()
{
    writefln("%s", (3 + 1i) + (4 - 1i));
    writefln("%s", (5 - 9i) - (2 + 6i));
    writefln("%s", (5 + 3i) * (5 + 8i));
    writefln("%s", (9 - 7i) / (9 - 3i));
    writefln("%s", abs(2 + 3i));
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# open Complex;;
# add { re = 3.0; im = 1.0 } { re = 4.0; im = -1.0 };;
- : Complex.t = {re = 7.; im = 0.}
# sub { re = 5.0; im = -9.0 } { re = 2.0; im = 6.0 };;
- : Complex.t = {re = 3.; im = -15.}
# mul { re = 5.0; im = 3.0 } { re = 5.0; im = 8.0 };;
- : Complex.t = {re = 1.; im = 55.}
# div { re = 9.0; im = -7.0 } { re = 9.0; im = -3.0 };;
- : Complex.t = {re = 1.1333333333333333; im = -0.4}
# norm { re = 2.0; im = 3.0 };;
- : float = 3.60555127546398957

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
>> require 'complex'
>> puts Complex(3.0, 1.0) + Complex(4.0, -1.0)
7.0+0.0i
>> puts Complex(5.0, -9.0) - Complex(2.0, 6.0)
3.0-15.0i
>> puts Complex(5.0, 3.0) * Complex(5.0, 8.0)
1.0+55.0i
>> puts Complex(9.0, -7.0) / Complex(9.0, -3.0)
1.13333333333333-0.4i
>> puts Complex(2.0, 3.0).abs
3.60555127546399

×整数にメッセージ i を → ○実数にメッセージ i を


F#(fsi)での実行例
dll の読み込みは、オプションでもできます。
1
2
3
4
5
6
7
> #r "FSharp.PowerPack.dll";;
> open Math.Complex;;
> (complex 3. 1.) + (complex 4. -1.);;
> (complex 5. -9.) - (complex 2. 6.);;
> (complex 5. 3.) * (complex 5. 8.);;
> (complex 9. -7.) / (complex 9. -3.);;
> magnitude (complex 2. 3.) ;;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
>> require 'complex'
>> puts (3.0 + 1.0.im) + (4.0 - 1.0.im)
7.0+0.0i
>> puts (5.0 - 9.0.im) - (2.0 + 6.0.im)
3.0-15.0i
>> puts (5.0 + 3.0.im) * (5.0 + 8.0.im)
1.0+55.0i
>> puts (9.0 - 7.0.im) / (9.0 - 3.0.im)
1.13333333333333-0.4i
>> puts (2.0 + 3.0.im).abs
3.60555127546399

結果を整形する場合には、
> printfn "%O" ((complex 3. 1.) + (complex 4. -1.));;
とかして下さい。

言語は ViViScript
実行結果:
(7, 0)
(3, -15)
(1, 55)
(1.13333, -0.4)
3.60555

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class complex
{
    function complex(r, i)
    {
        this.r = double(r);        //    実数部
        this.i = double(i);        //    虚数部
    }
    function format() { return "(" + this.r + ", " + this.i + ")"; }
}
function complex_add(lhs, rhs)
{
    return new complex(lhs.r + rhs.r, lhs.i + rhs.i);
}
function complex_sub(lhs, rhs)
{
    return new complex(lhs.r - rhs.r, lhs.i - rhs.i);
}
function complex_mul(lhs, rhs)
{
    return new complex(lhs.r * rhs.r - lhs.i * rhs.i, lhs.r * rhs.i + lhs.i * rhs.r);
}
function complex_div(lhs, rhs)
{
    $t = (rhs.r * rhs.r + rhs.i * rhs.i);
    return new complex((lhs.r * rhs.r + lhs.i * rhs.i) / $t, (lhs.i * rhs.r - lhs.r * rhs.i) / $t);
}
function complex_abs(c)
{
    return Math.sqrt(c.r * c.r + c.i * c.i);
}

cout << complex_add(new complex(3, 1), new complex(4, -1)).format() << "\n";
cout << complex_sub(new complex(5, -9), new complex(2, 6)).format() << "\n";
cout << complex_mul(new complex(5, 3), new complex(5, 8)).format() << "\n";
cout << complex_div(new complex(9, -7), new complex(9, -3)).format() << "\n";
cout << complex_abs(new complex(2, 3)) << "\n";

絶対値を求めるのに必要な平方根を求める関数が標準では用意されないので頑張って作ってみたりなど、本質でない部分に労力が... 使えるならEXSLTを使うといいかも。

下記のようなxmlにxsltを適応すると計算できます。:

<complex-list>
  <add>
    <complex real="3" imag="1" />
    <complex real="4" imag="-1" />
  </add>
  <sub>
    <complex real="5" imag="-9" />
    <complex real="2" imag="6" />
  </sub>
  <mul>
    <complex real="5" imag="3" />
    <complex real="5" imag="8" />
  </mul>
  <div>
    <complex real="9" imag="-7" />
    <complex real="9" imag="-3" />
  </div>
  <abs>
    <complex real="2" imag="3" />
  </abs>
</complex-list>
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:fn="http://www.w3.org/2005/xpath-functions"
  xmlns:my="uri:ja.doukaku.org:my-functions"
  exclude-result-prefixes="my"
  >

  <xsl:output method="text" />

  <xsl:template match="/complex-list" >
    <xsl:for-each select="complex|add|sub|mul|div|abs">
      <xsl:variable name="complex" as="xs:decimal*">
        <xsl:sequence select="my:evaluate-node(.)" />
      </xsl:variable>
      <xsl:value-of select="my:complex-to-string($complex[1], $complex[2])" />
      <xsl:text>&#xA;</xsl:text>
    </xsl:for-each>
  </xsl:template>

  <xsl:function name="my:complex-to-string" as="xs:string">
    <xsl:param name="real" as="xs:decimal" />
    <xsl:param name="imag" as="xs:decimal" />

    <xsl:variable name="realstr" as="xs:string" select="xs:string($real)" />
    <xsl:variable name="imagsign" as="xs:string">
      <xsl:choose>
        <xsl:when test="$imag gt 0">
          <xsl:value-of select="'+'" />
        </xsl:when>
        <xsl:when test="$imag lt 0">
          <xsl:value-of select="'-'" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="''" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="imagstr" as="xs:string">
      <xsl:choose>
        <xsl:when test="fn:abs($imag)=1.0">
          <xsl:value-of select="''" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="fn:abs($imag)" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$imag=0">
        <xsl:value-of select="$realstr" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="fn:string-join(($realstr, $imagsign, fn:concat($imagstr, 'i')), ' ')" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="my:evaluate-node" as="xs:decimal*">
    <xsl:param name="node" as="node()" />

    <xsl:variable name="node-name" as="xs:string" select="fn:name($node)" />
    <xsl:variable name="complex" as="xs:decimal*">
      <xsl:for-each select="$node/*">
        <xsl:sequence select="my:evaluate-node(.)" />
      </xsl:for-each>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$node-name = 'complex'">
        <xsl:sequence select="$node/@real" />
        <xsl:choose>
          <xsl:when test="fn:exists($node/@imag)">
            <xsl:sequence select="$node/@imag" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:sequence select="0" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:when test="$node-name = 'add'">
        <xsl:sequence select="my:evaluate-add($complex)" />
      </xsl:when>
      <xsl:when test="$node-name = 'sub'">
        <xsl:sequence select="my:evaluate-sub($complex)" />
      </xsl:when>
      <xsl:when test="$node-name = 'mul'">
        <xsl:sequence select="my:evaluate-mul($complex)" />
      </xsl:when>
      <xsl:when test="$node-name = 'div'">
        <xsl:sequence select="my:evaluate-div($complex)" />
      </xsl:when>
      <xsl:when test="$node-name = 'abs'">
        <xsl:sequence select="my:evaluate-abs($complex)" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:message terminate="yes">
          <xsl:text>*** unknown element name </xsl:text>
          <xsl:value-of select="$node-name" />
          <xsl:text> ***</xsl:text>
        </xsl:message>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="my:evaluate-add" as="xs:decimal*">
    <xsl:param name="values" as="xs:decimal*" />

    <xsl:choose>
      <xsl:when test="fn:empty($values)">
        <xsl:sequence select="(0,0)" />
      </xsl:when>
      <xsl:when test="fn:count($values)=2">
        <xsl:sequence select="$values" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="intermediate" as="xs:decimal*">
          <xsl:sequence select="$values[1] + $values[3]" />
          <xsl:sequence select="$values[2] + $values[4]" />
          <xsl:sequence select="$values[fn:count(.) gt 4]" />
        </xsl:variable>
        <xsl:sequence select="my:evaluate-add($intermediate)" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="my:evaluate-sub" as="xs:decimal*">
    <xsl:param name="values" as="xs:decimal*" />

    <xsl:choose>
      <xsl:when test="fn:empty($values)">
        <xsl:sequence select="(0,0)" />
      </xsl:when>
      <xsl:when test="fn:count($values)=2">
        <xsl:sequence select="$values" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="intermediate" as="xs:decimal*">
          <xsl:sequence select="$values[1] - $values[3]" />
          <xsl:sequence select="$values[2] - $values[4]" />
          <xsl:sequence select="$values[fn:count(.) gt 4]" />
        </xsl:variable>
        <xsl:sequence select="my:evaluate-sub($intermediate)" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="my:evaluate-mul" as="xs:decimal*">
    <xsl:param name="values" as="xs:decimal*" />

    <xsl:choose>
      <xsl:when test="fn:empty($values)">
        <xsl:sequence select="(0,0)" />
      </xsl:when>
      <xsl:when test="fn:count($values)=2">
        <xsl:sequence select="$values" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="intermediate" as="xs:decimal*">
          <xsl:sequence select="$values[1] * $values[3] - $values[2] * $values[4]" />
          <xsl:sequence select="$values[1] * $values[4] + $values[2] * $values[3]" />
          <xsl:sequence select="$values[fn:count(.) gt 4]" />
        </xsl:variable>
        <xsl:sequence select="my:evaluate-mul($intermediate)" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="my:evaluate-div" as="xs:decimal*">
    <xsl:param name="values" as="xs:decimal*" />

    <xsl:choose>
      <xsl:when test="fn:empty($values)">
        <xsl:sequence select="(0,0)" />
      </xsl:when>
      <xsl:when test="fn:count($values)=2">
        <xsl:sequence select="$values" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="intermediate" as="xs:decimal*">
          <xsl:variable name="d" as="xs:decimal"
            select="$values[3] * $values[3] + $values[4] * $values[4]" />
          <xsl:sequence select="($values[1] * $values[3] + $values[2] * $values[4]) div $d" />
          <xsl:sequence select="($values[1] * $values[4] - $values[2] * $values[3]) div $d" />
          <xsl:sequence select="$values[fn:count(.) gt 4]" />
        </xsl:variable>
        <xsl:sequence select="my:evaluate-div($intermediate)" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="my:evaluate-abs" as="xs:decimal*">
    <xsl:param name="values" as="xs:decimal*" />

    <xsl:sequence select="my:sqrt($values[1] * $values[1] + $values[2] * $values[2])" />
    <xsl:sequence select="0" />
  </xsl:function>

  <xsl:function name="my:sqrt" as="xs:decimal">
    <xsl:param name="n" as="xs:decimal" />
    <xsl:variable name="base" as="xs:integer*">
      <xsl:variable name="nstr" as="xs:string" select="xs:string($n)" />
      <xsl:for-each select="0 to
        ($n idiv fn:string-length(if (fn:contains($nstr, '.'))
                                  then (fn:substring-before($nstr, '.'))
                                  else ($nstr)))" >
        <xsl:if test=". * . ge $n">
          <xsl:sequence select="." />
        </xsl:if>
      </xsl:for-each>
    </xsl:variable>
    <xsl:value-of select="my:sqrt-search($n, $base[1], 10)" />
  </xsl:function>

  <xsl:function name="my:sqrt-search-base" as="xs:integer" >
    <xsl:param name="n" as="xs:decimal" />
    <xsl:param name="m" as="xs:integer" />

    <xsl:choose>
      <xsl:when test="$m * $m lt $n">
        <xsl:value-of select="my:sqrt-search-base($n, $m + 1)" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$m" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="my:sqrt-search">
    <xsl:param name="n" as="xs:decimal" />
    <xsl:param name="m" as="xs:decimal" />
    <xsl:param name="prec" as="xs:integer" />

    <xsl:choose>
      <xsl:when test="$prec = 0">
        <xsl:value-of select="$m" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="my:sqrt-search($n, (($m + ($n div $m)) div 2), $prec - 1)" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>
</xsl:stylesheet>

122,143,164,187行目の fn:count(.) gt 4 は fn:position() gt 4 の間違いでした。

何という恥ずかしいミス...

つーわけで、自分で-1


使うときに楽だろうと思い、引数の型に幅を持たせてみました。

例)
var c0 = new Complex(0, 1);
var c1 = new Complex([1, 1]);
var c2 = new Complex({r:3, i:-4});
var c3 = new Complex("5-8i");

alert((new Complex("3+2i")).mul("5-i").mul("-6+2i").div("5-i").div("-6+2i"));
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
var Complex = function (arg0, arg1){
    arg0 = arg0 || 0;
    arg1 = arg1 || 0;
    if (typeof arg0 == "number" && typeof arg1 == "number"){
        this.r = arg0;
        this.i = arg1;
    } else {
        var tmp = Complex.conv(arg0)
        this.r = tmp.r;
        this.i = tmp.i;
    }
};

// 加減乗除メソッドは破壊的
Complex.prototype = {
    toString: function(){return Complex.toString(this);},
    valueOf:  function(){return Complex.toString(this);},
    abs: function(){return Complex.abs(this);},
    add: function(cn){
        var tmp = Complex.add(this, cn);
        this.r = tmp.r;
        this.i = tmp.i;
        return this;
    },
    sub: function(cn){
        var tmp = Complex.sub(this, cn);
        this.r = tmp.r;
        this.i = tmp.i;
        return this;
    },
    mul: function(cn){
        var tmp = Complex.mul(this, cn);
        this.r = tmp.r;
        this.i = tmp.i;
        return this;
    },
    div: function(cn){
        var tmp = Complex.div(this, cn);
        this.r = tmp.r;
        this.i = tmp.i;
        return this;
    }
};

// 以下はインスタンスのメソッドではない
// 引数をインスタンスもどき(メソッドなしでプロパティr, iのみのオブジェクト)に変換する関数
Complex.conv = function(arg){
    if (typeof arg == "object") {
        return {r: Number(arg.r || arg[0] || 0), i: Number(arg.i || arg[1] || 0)};
    } else if (typeof arg == "string") {
        var srcNum = "([+\\-]?(?:[0-9]+\\.?[0-9]*|0?\\.[0-9]+)(?:e[+\\-]?[0-9]+)?)";
        var reCNum = new RegExp("^(?:" + srcNum + "(?!i))?(?:" + srcNum + "i)?$", "i");
        reCNum.exec(arg.replace(/\s/g, "").replace(/(^|\+|-)i/i, "$11i"));
        return {r: Number(RegExp.$1), i: Number(RegExp.$2)};
    }
    return {r: Number(arg), i: 0};
};

// インスタンス相当を引数に取る関数
Complex.toString = function(cn){
    cn = Complex.conv(cn);
    return cn.r.toString() + (cn.i >= 0 ? "+" : "") + cn.i.toString() + "i";
};
Complex.abs = function(cn){
    cn = Complex.conv(cn);
    return Math.sqrt(cn.r * cn.r + cn.i * cn.i);
};
// 加減乗除関数は新しいインスタンスを返す
Complex.add = function(cn0, cn1){
    cn0 = Complex.conv(cn0);
    cn1 = Complex.conv(cn1);
    return new Complex(cn0.r + cn1.r, cn0.i + cn1.i);
};
Complex.sub = function(cn0, cn1){
    cn0 = Complex.conv(cn0);
    cn1 = Complex.conv(cn1);
    return new Complex(cn0.r - cn1.r, cn0.i - cn1.i);
};
Complex.mul = function(cn0, cn1){
    cn0 = Complex.conv(cn0);
    cn1 = Complex.conv(cn1);
    return new Complex(cn0.r * cn1.r - cn0.i * cn1.i,
                       cn0.i * cn1.r + cn0.r * cn1.i);
};
Complex.div = function(cn0, cn1){
    cn0 = Complex.conv(cn0);
    cn1 = Complex.conv(cn1);
    var absSq = cn1.r * cn1.r + cn1.i * cn1.i;
    return new Complex((cn0.r * cn1.r + cn0.i * cn1.i) / absSq,
                       (cn0.i * cn1.r - cn0.r * cn1.i) / absSq);
};
// 定義部はここまで

/* お題の計算。結果は以下
7+0i
3-15i
1+55i
1.1333333333333333-0.4i
3.605551275463989
*/
alert(
             Complex.add(new Complex(3, 1),  new Complex(4, -1))
    + "\n" + Complex.sub(new Complex(5, -9), new Complex(2, 6))
    + "\n" + Complex.mul(new Complex(5, 3),  new Complex(5, 8))
    + "\n" + Complex.div(new Complex(9, -7), new Complex(9, -3))
    + "\n" + Complex.abs(new Complex(2, 3))
);

// インスタンスを作る。引数は数値2つ、
// もしくは数値要素を2つ持つ(連想)配列か、複素数と解釈できる文字列
var c0 = new Complex(0, 1);
var c1 = new Complex([1, 1]);
var c2 = new Complex({r:3, i:-4});
var c3 = new Complex("5-8i");

// 絶対値を出してみる。上3行と下3行の結果は同じ。
alert(
             "|" + c0 + "| = " + Complex.abs(c0)
    + "\n" + "|" + c1 + "| = " + Complex.abs(c1)
    + "\n" + "|" + c2 + "| = " + Complex.abs(c2)
    + "\n" + "|" + c0 + "| = " + c0.abs()
    + "\n" + "|" + c1 + "| = " + c1.abs()
    + "\n" + "|" + c2 + "| = " + c2.abs()
);

// 計算1。引数なら文字列のままでも可。
// 下3行の計算は破壊的(c0の値が計算結果に変わる)
alert(
        "(" + c0 + ") + (" + c1   + ") = " + Complex.add(c0, c1)
    + "\n(" + c0 + ") - (" + c2   + ") = " + Complex.sub(c0, c2)
    + "\n(" + c0 + ") / (" + "-i" + ") = " + Complex.div(c0, "-i")
    + "\n(" + c0 + ") + (" + c1   + ") = " + c0.add(c1)
    + "\n(" + c0 + ") - (" + c2   + ") = " + c0.sub(c2)
    + "\n(" + c0 + ") / (" + "-i" + ") = " + c0.div("-i")
);

// 計算2。iの2乗。加減乗除の組み合わせ2つ。複素数を0で割ると0/0
alert(
      "i * i = " + Complex.mul("i", "i")

    + "\n(3+2i) * (5-i) * (-6+2i) / (5-i) / (-6+2i) = "
    + (new Complex("3+2i")).mul("5-i").mul("-6+2i").div("5-i").div("-6+2i")

    + "\n( (3+2i) + (4-i) ) * 2i * -.5i - (4-i) = "
    + Complex.add("3+2i", "4-i").mul("2i").mul("-.5i").sub("4-i")

    + "\n(1+2i) / 0 = " + Complex.div("1+2i", "0")
);

// 引数いろいろ。falsyな値や空配列は0+0iに
var testcases = [
    "-3-8i", "5", [0, 4], [2, -8],
    "-2+i", "-2-i", {r:-2.5, i:3e-2}, "-2E8 + I",
    "0", "i", Infinity, NaN, "", {}, null, undefined
];
for (var i = 0, rslt = ""; i < testcases.length; i++){
    rslt += (typeof testcases[i]) + ": " + testcases[i]
        + "\n\t\t" + (new Complex(testcases[i])) + "\n";
}
alert(rslt);

SQL Server 2008 で確認しました。

入力が微妙ですが、問題ID, 種類(左辺:1、演算子:2、右辺:3), 実部, 虚部, 演算子(加算:1、減算:2、乗算:3、除算:4、絶対値:5)を与えます。

すると、Resultsとして問題IDの答えの実部と虚部が取得できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
WITH
  Input(id, kind, real_part, img_part, op) AS (
    -- (3 + i) + (4 - i)
    SELECT 1, 1, 3, 1, CAST(NULL AS int)
    UNION ALL
    SELECT 1, 2, NULL, NULL, 1
    UNION ALL
    SELECT 1, 3, 4, -1, NULL
    UNION ALL
    -- (5 - 9i) - (2 + 6i)
    SELECT 2, 1, 5, -9, NULL
    UNION ALL
    SELECT 2, 2, NULL, NULL, 2
    UNION ALL
    SELECT 2, 3, 2, 6, NULL
    UNION ALL
    -- (5 + 3i) * (5 + 8i)
    SELECT 3, 1, 5, 3, NULL
    UNION ALL
    SELECT 3, 2, NULL, NULL, 3
    UNION ALL
    SELECT 3, 3, 5, 8, NULL
    UNION ALL
    -- (9 - 7i) / (9 - 3i)
    SELECT 4, 1, 9, -7, NULL
    UNION ALL
    SELECT 4, 2, NULL, NULL, 4
    UNION ALL
    SELECT 4, 3, 9, -3, NULL
    UNION ALL
    -- |2 + 3i|
    SELECT 5, 1, 2, 3, NULL
    UNION ALL
    SELECT 5, 2, NULL, NULL, 5
  )
, Interval(id, l_real, l_img, op, r_real, r_img) AS (
    SELECT
        id
      , SUM(CASE kind WHEN 1 THEN real_part ELSE 0 END)
      , SUM(CASE kind WHEN 1 THEN img_part ELSE 0 END)
      , SUM(CASE kind WHEN 2 THEN op ELSE 0 END)
      , SUM(CASE kind WHEN 3 THEN real_part ELSE 0 END)
      , SUM(CASE kind WHEN 3 THEN img_part ELSE 0 END)
    FROM
        Input
    GROUP BY
        id
  )
, Results(id, real_part, img_part) AS (
    SELECT
        id
      , CASE op
        WHEN 1 THEN l_real + r_real
        WHEN 2 THEN l_real - r_real
        WHEN 3 THEN (l_real * r_real) - (l_img * r_img)
        WHEN 4 THEN ((l_real * r_real) + (l_img * r_img)) /
                    (SQUARE(r_real) + SQUARE(r_img))
        WHEN 5 THEN SQRT(SQUARE(l_real) + SQUARE(l_img))
        END
      , CASE op
        WHEN 1 THEN l_img + r_img
        WHEN 2 THEN l_img - r_img
        WHEN 3 THEN (l_img * r_real) + (l_real * r_img)
        WHEN 4 THEN ((l_img * r_real) - (l_real * r_img)) /
                    (SQUARE(r_real) + SQUARE(r_img))
        WHEN 5 THEN 0
        END
    FROM
        Interval
  )
SELECT * FROM Results

演算子オーバーロードを使ってスクラッチで実装。 Perlの真骨頂。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
#!/usr/bin/perl
use strict;
use warnings;

package ComplexNumber;
use overload
    '""' => \&toString,
    '+'  => \&add,
    '-'  => \&sub,
    '*'  => \&mul,
    '/'  => \&div,
    '0+' => \&val,
;
sub new{
    my ($class, $real, $imagin) = @_;
    return unless defined($real);
    
    if($real =~ /^[-+]?\d+(\.\d+)?$/ and 
       (!defined($imagin) or $imagin =~ /^[-+]?\d*(\d\.\d+)?i?$/))
    {#$real, $imagin両方に数値が渡ってきた時。$imaginが未定義/末尾にiは許容
        $real   =~ s/\+//;
        $imagin =~ s/[i+]//g if $imagin;
        $imagin = 0 unless $imagin;
        return bless {a=>$real, b=>$imagin}, $class;
    }
    return if $imagin;
    if($real =~ /^[-+]?\d+(\.\d+)?i$/){#第1引数 に 文字列'5i'とかが渡された時
        $real =~ s/[i+]//g;
        return bless {a=>0, b=>$real}, $class;
    }
    $real =~ s/\s//g;
    if(my ($real2, $imagin2) = $real =~ /^([-+]?\d+(?:\.\d+)?)([-+]\d+(?:\.\d+)?)i$/){
    #第1引数 に 文字列(ex. '5+4.8i')が渡された時
        $real2 =~ s/\+//;
        $imagin2 =~ s/\+//;
        return bless {a=>$real2, b=>$imagin2}, $class;
    }
    return;
}
sub toString{
    my $self = shift;
    return $self->{'a'} if $self->{'b'} == 0;
    return (abs($self->{'b'}) != 1 ? $self->{'b'} : '-') . 'i'
        if $self->{'a'} == 0;
    return $self->{'a'} . 
           ($self->{'b'} > 0 ? '+' : '') . 
           (abs($self->{'b'}) != 1 ? $self->{'b'} : '-') .'i';
}
sub add{
    my ($self, $src) = @_;
    $src = ComplexNumber->new($src) unless eval{$src->isa('ComplexNumber')};
    return $src ?
        ComplexNumber->new($self->{'a'}+$src->{'a'}, $self->{'b'}+$src->{'b'}) : ();
}
sub sub{
    my ($dest, $src, $rev) = @_;
    $src = ComplexNumber->new($src) unless eval{$src->isa('ComplexNumber')};
    return unless $src;
    ($dest, $src) = ($src, $dest) if $rev;
    return ComplexNumber->new($dest->{'a'}-$src->{'a'}, $dest->{'b'}-$src->{'b'});
}
sub mul{
    my ($dest, $src) = @_;
    $src = ComplexNumber->new($src) unless eval{$src->isa('ComplexNumber')};
    return $src ?
        ComplexNumber->new(
            $dest->{'a'}*$src->{'a'} - $dest->{'b'}*$src->{'b'},
            $dest->{'a'}*$src->{'b'} + $dest->{'b'}*$src->{'a'}
        ) : ();
}
sub div{
    my ($dest, $src, $rev) = @_;
    $src = ComplexNumber->new($src) unless eval{$src->isa('ComplexNumber')};
    return unless $src;
    ($dest, $src) = ($src, $dest) if $rev;
    return ComplexNumber->new(
        ($dest->{'a'}*$src->{'a'}+$dest->{'b'}*$src->{'b'})/($src->{'a'}**2 + $src->{'b'}**2),
        ($dest->{'b'}*$src->{'a'}-$dest->{'a'}*$src->{'b'})/($src->{'a'}**2 + $src->{'b'}**2),
    );
}
sub abs{
    my $self = shift;
    return sqrt($self->{'a'}**2 + $self->{'b'}**2)
}
sub val{
    my $self = shift;
    return $self->{'a'};
}

package main;

my $comp1 = ComplexNumber->new(8, 6.3);
my $comp2 = ComplexNumber->new('4 - 8.5i');

print $comp1 + $comp2 ."\n";
print $comp1 - $comp2 ."\n";
print $comp1 * $comp2 ."\n";
print $comp1 / $comp2 ."\n\n";

print $comp1 + 8 ."\n";
print $comp1 - 8 ."\n";
print 8 - $comp1 ."\n";
print $comp1 * 8 ."\n";
print $comp1 / 8 ."\n";
print 8 / $comp1 ."\n";

print $comp1->abs;

#8851をパラメタ付に改造してみました。 Complex[Int],Complex[Double]

もう、ぐだぐだ。

制限事項 整数と実数の混合ができない orz

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// 複素数(お題:http://ja.doukaku.org/247/)
// http://ja.doukaku.org/comment/----/
// snaさん作を改変( : http://ja.doukaku.org/comment/8851/)
// 参考 : http://en.literateprograms.org/Complex_numbers_(Scala)

trait Arithmetic[T<:AnyVal]{
  def unary_+ : T
  def unary_- : T
  def + (that:T):T
  def - (that:T):T
  def * (that:T):T
  def / (that:T):T
  def abs : T
  //
  def lt0 : Boolean  // >   0
  def gt0 : Boolean  // <   0
  def eq0 : Boolean  // ==  0
  //
  def eqp1 : Boolean // ==  1
  def eqm1 : Boolean // == -1
  //
}

case class Complex[ T<%Arithmetic[T] ](real:T, imag:T) {
  // +(a + bi) = (a + bi)
  def unary_+ = this
  
  // -(a + bi) = (-a - bi)
  def unary_- = Complex[T](-real, -imag)
  
  // (a + bi) + (c + di) = (a + c) + (b + d)i
  def + (that: Complex[T]) = Complex(this.real + that.real, this.imag + that.imag)
  
  // (a + bi) - (c + di) = (a - c) + (b - d)i
  def - (that: Complex[T]) = Complex(this.real - that.real, this.imag - that.imag)
  
  // (a + bi) * (c + di) = (ac - bd) + (bc + ad)i
  def * (that: Complex[T]) = {
    val Complex(a, b) = this
    val Complex(c, d) = that
    Complex(a*c - b*d, b*c + a*d)
  }
  
  // (a + bi) / (c + di) = (ac + bd) / (c^2 + d^2) + (bc - ad) / (c^2 + d^2)
  def / (that: Complex[T]) = {
    val Complex(a, b) = this
    val Complex(c, d) = that
    val deno = c*c + d*d
    Complex((a*c + b*d) / deno, (b*c - a*d) / deno)
  }
  
  // Conjugate
  def conjugate() : Complex[T] = Complex(real,-imag)
  
  override def toString = this match {
    case Complex(re, im) if im.eq0            => re.toString
    case Complex(re, im) if re.eq0 && im.eqp1 => "i"
    case Complex(re, im) if re.eq0 && im.eqm1 => "-i"
    case Complex(re, im) if re.eq0            => im.toString + "i"
    case Complex(re, im) if           im.eqp1 => re.toString + " + i"
    case Complex(re, im) if           im.eqm1 => re.toString + " - i"
    case Complex(re, im) if           im.gt0  => re.toString + " + " + im.toString + "i"
    case Complex(re, im) if           im.lt0  => re.toString + " - " + im.abs.toString + "i"
  }

}

object test{
  implicit def int2Arithmeic(n:Int) : Arithmetic[Int] = 
                    new Arithmetic[Int]{
                         def unary_+ : Int  = n.unary_+
                         def unary_- : Int  = n.unary_-
                         def + (that:Int):Int = n+that
                         def - (that:Int):Int = n-that
                         def * (that:Int):Int = n*that
                         def / (that:Int):Int = n/that
                         def abs = Math.abs(n)
                         //
                         def lt0 = n<0
                         def gt0 = n>0
                         def eq0 = n==0
                         //
                         def eqp1 = n==1 
                         def eqm1 = n== -1  }
  
  implicit def double2Arithmeic(n:Double) : Arithmetic[Double] = 
                    new Arithmetic[Double]{
                         def unary_+ : Double  = n.unary_+
                         def unary_- : Double  = n.unary_-
                         def + (that:Double):Double = n+that
                         def - (that:Double):Double = n-that
                         def * (that:Double):Double = n*that
                         def / (that:Double):Double = n/that
                         def abs = Math.abs(n)
                         //
                         def lt0 = n<0
                         def gt0 = n>0
                         def eq0 = n==0
                         //
                         def eqp1 = n==1 
                         def eqm1 = n== -1  }
  
  implicit def int2Complex   (n:Int   ):Complex[Int   ] = Complex(n,0)
  implicit def double2Complex(n:Double):Complex[Double] = Complex(n,0)
  implicit def icomp2dcomp   (z:Complex[Int]):Complex[Double] = Complex(z.real,z.imag)
  
  implicit def dcomp2richer  (z:Complex[Double]) = new Proxy{
       val self=z
       def abs = self match {
         case Complex(re, im) => Math.sqrt(re*re + im*im)
       }
    }
  
  implicit def icomp2richer  (z:Complex[int]) = new Proxy{
       val self=z
       def abs = self match {
         case Complex(re, im) => Math.sqrt(re*re + im*im)
       }
    }
  
  
  def main( args:Array[String] ) : Unit = {
    {
      val i = Complex(0,1)
      println( (3 + i  ) + (4 - i  ) )
      println( (5 - 9*i) - (2 + 6*i) )
      println( (5 + 3*i) * (5 + 8*i) )
      println( (9 - 7*i) / (9 - 3*i) )
      println( (2 + 3*i).abs         )
    }
    
    {
      val i = Complex(0.,1.)
      println( (3. + i  ) + (4. - i  ) )
      println( (5. - 9.*i) - (2. + 6.*i) )
      println( (5. + 3.*i) * (5. + 8.*i) )
      println( (9. - 7.*i) / (9. - 3.*i) )
      println( (2. + 3.*i).abs         )
    }
  }
}

Groovyで。結果は以下の通り。 .iあたりが気に入っている。

7.0+0.0i 3.0-15.0i 1.0+55.0i 1.1333333333333333-0.4i 3.605551275463989

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Complex {
  double re
  double im

  Complex(re, im) { this.re = re; this.im = im }
  Complex plus(c) { new Complex(re+c.re, im+c.im) }
  Complex minus(c) { new Complex(re-c.re, im-c.im)  }
  Complex multiply(c) { new Complex(re*c.re - im*c.im, re*c.im + im*c.re) }
  Complex div(c) {
    def denom = (c.re ** 2) + (c.im ** 2)
    new Complex((re*c.re+im*c.im)/denom, (im*c.re-re*c.im)/denom)
  }
  double abs(){ Math.sqrt(re ** 2 + im ** 2) }
  static final i = new Complex(0, 1)
  String toString() { re+(im>=0?'+':'')+im+'i' }
}

['plus','minus','multiply','div'].each {
  Number.metaClass."$it" = { Complex c -> new Complex(delegate, 0)."$it"(c) }
}
Number.metaClass.getI = {new Complex(0, delegate)}


def i = Complex.i

println ((3 + i) + (4 - i))
println ((5 - 9.i) - (2 + 6.i))
println ((5 + 3.i) * (5 + 8.i))
println ((9 - 7.i) / (9 - 3.i))
println ((2 - 3.i).abs())

Index

Feed

Other

Link

Pathtraq

loading...