使用Java生成法莱数列

在上一篇《法莱数列》数列中简要地介绍了法莱数列的特性、如何生成一组法莱数列,以及如何获得指定最大分母的法莱数列的个数。

在这一篇中,我们采用 Java 语言通过其特性来生成法莱数列。由于涉及分数运算,分数类直接就使用 Apache Commons Lang,这个包里有着许多有用的工具类,众多的 Java 开源产品中有许多也引用了这一类库,在这里仅用到 Fraction 类。

为了让各个功能进行模块化管理,设计了三个类:

  • Farey:用于生成法莱数列的类,其中有获得所有指定数的法莱数列和数列个数的一些方法;
  • FractionUtil:分数的工具类,这里主要有分数数组的成批输出和按照数学的分式形式进行输出等方法;
  • FareyTest:用于测试/生成法莱数列。

下面是这三个文件的源代码:

FareyTest.java

import  org.apache.commons.lang.math.Fraction;

public class
 FareyTest {

    
public static void
 main(String[] args) {
        
// 构造一个分母不大于5的法莱数列

        Farey farey = new Farey(5 );
        
// 获得法莱数列

        Fraction[] fareys =  farey.getFaleys();
        
// 以单行形式输出

        FractionUtil.toString(fareys);
        
// 以数学分式形式输出

        FractionUtil.toFractionString(fareys);
    }
}

Farey.java

import  org.apache.commons.lang.math.Fraction;

public class
 Farey {

    
/**

     * 法莱数列最大的分母数
     
*/
    
private int maxDenominator = 0 ;

    
/**

     * 法莱数列的个数
     
*/
    
private int groups = 0 ;

    
/**

     * 构造一个分母不大于max的法莱数列
     * 
@param  max
     
*/

    
public Farey(int  max) {
        setMax(max);
    }

    
public int
 getMaxDenominator() {
        
return this
.maxDenominator;
    }

    
public void setMax(int
 maxDenominator) {
        
// 法莱数列的最大的分母必须不小于2

        if (maxDenominator < 2 ) {
            
throw new IllegalArgumentException("数列分母的最大数不能小于2"
);
        }
        
this.maxDenominator =
 maxDenominator;
        
this.groups = 0
;
    }

    
/**

     * 获得分母不大于max法莱数列的个数
     * 
@return  法莱数列的个数
     
*/

    
public int  getFareyNumbers() {
        
if (groups != 0
) {
            
return
 groups;
        }
        
for (int i = 2; i <= maxDenominator; i++
) {
            groups
++
;
            
for (int j = 2; j < i; j++
) {
                
if (gcd(i, j) == 1
) {
                    groups
++
;
                }
            }
        }
        
return
 groups;
    }

    
/**

     * 获得分母不大于max的法莱数列分数数组
     * 
@return  法莱数列分数数组
     
*/

    
public  Fraction[] getFaleys() {
        
int groups =
 getFareyNumbers();
        Fraction[] fareys 
= new
 Fraction[groups];
        fareys[
0= Fraction.getFraction(1
, maxDenominator);
        
if (groups > 1
) {
            fareys[
1= Fraction.getFraction(1, maxDenominator - 1
);
        }
        
for (int i = 2; i < groups; i++
) {
            fareys[i] 
= getNextFarey(fareys[i - 2], fareys[i - 1
]);
        }
        
return
 fareys;
    }

    
/**

     * 根据法莱数列的前两个分数,获得第三个分数
     * 
@param  f1 第一个分数
     * 
@param
 f2 第二个分数
     * 
@return
 法莱数列的第三个分数
     
*/

    
private  Fraction getNextFarey(Fraction f1, Fraction f2) {
        
int multiple = (maxDenominator + f1.getDenominator()) /
 f2.getDenominator();
        
int numerator = multiple * f2.getNumerator() -
 f1.getNumerator();
        
int denominator = multiple * f2.getDenominator() -
 f1.getDenominator();
        
return
 Fraction.getFraction(numerator, denominator).reduce();
    }

    
/**

     * 求两个数的最大公约数,经典算法哦
     
*/
    
private int gcd(int m, int  n) {
        
if (n == 0
) {
            
return
 m;
        }
        
return gcd(n, m %
 n);
    }
}

FractionUtil.java

import  org.apache.commons.lang.math.Fraction;

public class
 FractionUtil {   
    
    
/**

     * 以单行形式输出分数数组,以逗号分隔
     * 
@param  fracs 分数数组
     
*/

    
public static void  toString(Fraction[] fracs) {
        
for (int i = 0, k = fracs.length - 1; i < k; i++
) {
            System.out.print(fracs[i].toString() 
+ ""
);
        }
        System.out.println(fracs[fracs.length 
- 1
].toString());
    }

    
/**

     * 以普通的分数形式(分子、分数线、分母的上中下式)输出分数数组
     * 
@param  fracs 分数数组
     
*/

    
public static void  toFractionString(Fraction[] fracs) {
        
char[] line = { '-''-''-''-''-''-''-''-''-''-'
 };
        
char[] space = { ' '' '' '' '' '' '' '' '' '' '
};
        
int[] width = new int
[fracs.length];
        
int[] numeratorWidth = new int
[fracs.length];
        
int[] denominatorWidth = new int
[fracs.length];
        
for (int i = 0; i < fracs.length; i++
) {
            numeratorWidth[i] 
=
 width(fracs[i].getNumerator());
            denominatorWidth[i] 
=
 width(fracs[i].getDenominator());
            width[i] 
=
 Math.max(numeratorWidth[i], denominatorWidth[i]);
        }
        
for (int i = 0; i < fracs.length; i++
) {
            System.out.print(
" "

                    
+ new String(space, 0, width[i] -  numeratorWidth[i])
                    
+ fracs[i].getNumerator() + "   "
);
        }
        System.out.println();
        
for (int i = 0; i < fracs.length; i++
) {
            System.out.print(
new String(line, 0, width[i] + 2+ "  "
);
        }
        System.out.println();
        
for (int i = 0; i < fracs.length; i++
) {
            System.out.print(
" "

                    
+ new String(space, 0, width[i] -  denominatorWidth[i])
                    
+ fracs[i].getDenominator() + "   "
);
        }
        System.out.println();
    }

    
/**

     * 获得一个数字的位数
     
*/
    
private static int width(int  num) {
        
int width = 0
;
        
while (num != 0
) {
            num 
/= 10
;
            width
++
;
        }
        
return
 width;
    }
    
    
private
 FractionUtil(){        
    }
}
评论 3 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

火龙果被占用了

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值