3.2 分数和复数
看其他篇章到目录 选择。
我们讲到数学的计算,难免会遇到分数形式,因为实数的定义就是可以表示为一个分数的形式的数,而加入虚数的复数也是偶尔会遇到的。 Commons Math包中的 fraction和 complex包就分别提供了方法来表示这两种数。
首先来看一个接口 FieldElement<T>,这个接口定义了一个泛型参数,其具体内容定义了 5组方法,分别是加减乘除运算和 getField()方法。具体 Field<T>是什么,这里就不研究了,因为我发现暂时还没有用到它。呵呵。
像这样的无算法和实现的类,具体就是看示例来观察它的运算行为了。
正式开始,先看看 Fraction类,在 fraction子包下的 Fraction类继承了 java中的 Number类,同时实现了 接口 FieldElement<Fraction>。 Fraction的构造方法有 5个,支持给定一个实数来构建分数,也支持给定分子分母的构建方法。具体的见代码吧,因为代码已经非常直观了。
1
/** */
/**
2
*
3
*/
4
package
algorithm.math;
5
6
import
org.apache.commons.math.complex.Complex;
7
import
org.apache.commons.math.fraction.Fraction;
8
import
org.apache.commons.math.fraction.FractionConversionException;
9
10
/** */
/**
11
* @author Jia Yu
12
* @date 2010-11-29
13
*/
14
public
class
FractionAndComplexTest
{
15
16
/** */ /**
17
* @param args
18
*/
19
public static void main(String[] args)
{
20
// TODO Auto-generated method stub
21
fraction();
22
System.out.println( " ------------------------------------------------ " );
23
complex();
24
}
25
26
private static void complex()
{
27
// TODO Auto-generated method stub
28
Complex z = new Complex( 3.0 , 4.0 );
29
Complex x = new Complex( 5.0 , 7.0 );
30
31
// output directly
32
System.out.println( " complex z = " + z); // ugly
33
System.out.println( " complex z = " + c2s(z)); // organized manually
34
System.out.println( " complex x = " + c2s(x));
35
36
// complex abs
37
System.out.println( " abs of z = " + z.abs());
38
// complex add
39
System.out.println( " z+x = " + c2s(z.add(x)));
40
// complex substrac
41
System.out.println( " z-x = " + c2s(z.subtract(x)));
42
// complex multiply
43
System.out.println( " z*x = " + c2s(z.multiply(x)));
44
// complex sin cos
45
System.out.println( " sin(z) = " + c2s(z.sin()));
46
System.out.println( " cos(z) = " + c2s(z.cos()));
47
// complex conjugate
48
System.out.println( " conjugate of z = " + c2s(z.conjugate()));
49
}
50
51
public static String c2s(Complex c)
{
52
if (c.getImaginary() < 0 )
53
return "" + c.getReal() + c.getImaginary() + " i " ;
54
return "" + c.getReal() + " + " + c.getImaginary() + " i " ;
55
}
56
57
private static void fraction()
{
58
// TODO Auto-generated method stub
59
Fraction frac1 = new Fraction( 2 , 3 );
60
61
// output directly
62
System.out.println( " frac1 = " + frac1);
63
64
try
{
65
Fraction frac2 = new Fraction( 0.5 );
66
System.out.println( " frac2 = " + frac2);
67
68
// fraction doublevalue
69
System.out.println( " frac1's double form is " + frac1.doubleValue());
70
// fraction add
71
System.out.println( " frac1+frac2 = " + frac1.add(frac2));
72
// fraction substract
73
System.out.println( " frac1-frac2 = " + frac1.subtract(frac2));
74
// fraction multiply
75
System.out.println( " frac1*frac2 = " + frac1.multiply(frac2));
76
// fraction divide
77
System.out.println( " frac1/frac2 = " + frac1.divide(frac2));
78
// fraction multiplicative inverse
79
System.out.println( " frac1's inverse is " + frac1.reciprocal());
80
81
// fraction reduction
82
System.out.println( " 5 / 25 = " + Fraction.getReducedFraction( 5 , 25 ));
83
} catch (FractionConversionException e)
{
84
// TODO Auto-generated catch block
85
e.printStackTrace();
86
}
87
}
88
89
}
90


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

看了具体用法,不免要探究一下,分数的这些运算在 Commons Math里是怎么实现的。跟我们直观感觉一样,在 Fraction类内部定义了分子和分母两个 int型的成员变量。我忍不住要把构造方法的源码贴上来:
1
private
Fraction(
double
value,
double
epsilon,
int
maxDenominator,
int
maxIterations)
2
throws
FractionConversionException
3
{
4
long overflow = Integer.MAX_VALUE;
5
double r0 = value;
6
long a0 = ( long )Math.floor(r0);
7
if (a0 > overflow)
{
8
throw new FractionConversionException(value, a0, 1l );
9
}
10
11
// check for (almost) integer arguments, which should not go
12
// to iterations.
13
if (Math.abs(a0 - value) < epsilon)
{
14
this .numerator = ( int ) a0;
15
this .denominator = 1 ;
16
return ;
17
}
18
19
long p0 = 1 ;
20
long q0 = 0 ;
21
long p1 = a0;
22
long q1 = 1 ;
23
24
long p2 = 0 ;
25
long q2 = 1 ;
26
27
int n = 0 ;
28
boolean stop = false ;
29
do
{
30
++ n;
31
double r1 = 1.0 / (r0 - a0);
32
long a1 = ( long )Math.floor(r1);
33
p2 = (a1 * p1) + p0;
34
q2 = (a1 * q1) + q0;
35
if ((p2 > overflow) || (q2 > overflow))
{
36
throw new FractionConversionException(value, p2, q2);
37
}
38
39
double convergent = ( double )p2 / ( double )q2;
40
if (n < maxIterations && Math.abs(convergent - value) > epsilon && q2 < maxDenominator)
{
41
p0 = p1;
42
p1 = p2;
43
q0 = q1;
44
q1 = q2;
45
a0 = a1;
46
r0 = r1;
47
} else
{
48
stop = true ;
49
}
50
} while ( ! stop);
51
52
if (n >= maxIterations)
{
53
throw new FractionConversionException(value, maxIterations);
54
}
55
56
if (q2 < maxDenominator)
{
57
this .numerator = ( int ) p2;
58
this .denominator = ( int ) q2;
59

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