Change Dir

先知cd——热爱生活是一切艺术的开始

统计

留言簿(18)

积分与排名

“牛”们的博客

各个公司技术

我的链接

淘宝技术

阅读排行榜

评论排行榜

Commons Math学习笔记——分数和复数

 

3.2 分数和复数

看其他篇章到目录选择。

我们讲到数学的计算,难免会遇到分数形式,因为实数的定义就是可以表示为一个分数的形式的数,而加入虚数的复数也是偶尔会遇到的。Commons Math包中的fractioncomplex包就分别提供了方法来表示这两种数。

首先来看一个接口FieldElement<T>,这个接口定义了一个泛型参数,其具体内容定义了5组方法,分别是加减乘除运算和getField()方法。具体Field<T>是什么,这里就不研究了,因为我发现暂时还没有用到它。呵呵。

像这样的无算法和实现的类,具体就是看示例来观察它的运算行为了。

正式开始,先看看Fraction类,在fraction子包下的Fraction类继承了java中的Number类,同时实现了接口FieldElement<Fraction>Fraction的构造方法有5个,支持给定一个实数来构建分数,也支持给定分子分母的构建方法。具体的见代码吧,因为代码已经非常直观了。

 1/**
 2 * 
 3 */

 4package algorithm.math;
 5
 6import org.apache.commons.math.complex.Complex;
 7import org.apache.commons.math.fraction.Fraction;
 8import org.apache.commons.math.fraction.FractionConversionException;
 9
10/**
11 * @author Jia Yu
12 * @date   2010-11-29
13 */

14public 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.04.0);
29        Complex x = new Complex(5.07.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

 

看了具体用法,不免要探究一下,分数的这些运算在Commons Math里是怎么实现的。跟我们直观感觉一样,在Fraction类内部定义了分子和分母两个int型的成员变量。我忍不住要把构造方法的源码贴上来:

 1private 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        }
 else {
60            this.numerator = (int) p1;
61            this.denominator = (int) q1;
62        }

63
64    }

65

 

为什么是私有的?因为这是最根本的构造方法,其他方法都是调用了这个基本方法。具体参数的解释:value代表了要转化的double值,epsilon表示了最大误差范围,maxDenominator表示支持的最大分母,maxIterations表示最大的渐进分数。这个构造方法最后得到了分子和分母的表示(numeratordenominator)。其他的运算代码就不用贴了,因为表示出了分数的分子分母,其他的运算容易实现(其实是很有趣的,看如何通分约分,利用gcd算法)。

分数的大分数表示有BigFraction类,具体的用法可以看源码。

下面是复数的实现:

关于复数的概念,Complex类里定义了两个double变量分别表示复数的实部real和虚部imaginary。复数的运算相比分数要简单一些,直观上看毕竟是一个线性组合,所以相对的加减乘除运算不涉及到通分和约分这样需要GCD才能做到的事情。具体的实现不多讲了,没有意义,直接上示例代码。因为比较简单,所以使用到的同学们直接用就可以了,需要改进的可以参看源码,其实complex包下的Complex类的源码也并不长。呵呵1k行而已。

 

程序输出结果:
frac1 = 2 / 3
frac2 = 1 / 2
frac1's double form is 0.6666666666666666
frac1+frac2 = 7 / 6
frac1-frac2 = 1 / 6
frac1*frac2 = 1 / 3
frac1/frac2 = 4 / 3
frac1's inverse is 3 / 2
5 / 25 = 1 / 5
------------------------------------------------
complex z = org.apache.commons.math.complex.Complex@a8780000
complex z = 3.0+4.0i
complex x = 5.0+7.0i
abs of z = 5.0
z+x = 8.0+11.0i
z-x = -2.0-3.0i
z*x = -13.0+41.0i
sin(z) = 3.853738037919377-27.016813258003932i
cos(z) = -27.034945603074224-3.851153334811777i
conjugate of z = 3.0-4.0i

相关资料:

复数:http://zh.wikipedia.org/zh-cn/%E5%A4%8D%E6%95%B0_%28%E6%95%B0%E5%AD%A6%29

Commons math包:http://commons.apache.org/math/index.html

posted on 2010-12-27 22:00 changedi 阅读(2140) 评论(0)  编辑  收藏 所属分类: 数学


只有注册用户登录后才能发表评论。


网站导航: