北大ACM 1001,关于高精度数的一些想法:

来自北京大学ACM的一道题目:http://poj.org/problem?id=1001&lang=zh-CN&change=true

 

       对于题目中的高精度幂,现成的应该没有哪一种数据类型可以直接进行运算(ps:好像JavaBigInteger 这种类可以,往后再多了解这个)。那该怎么办呢?

       大一那时候的想法是分段而行。怎么样分?例如 11111111112 ,可以转换为(11111*105+111112之流。但后来觉得不太可行,因为这会涉及到很多的10n,需要很多的标记,似乎也不好操控,特别是分得很细的时候。第二个想法是数组。但是遇到的问题还是从前一个想法继承下来了。后来也慢慢断绪了。

 

现在的这个想法的产生,应该说很大程度是归结于编程和语言操控能力的提高。因为算法的实现是基于很简单的道理。

1.      还是那样,大事化小:是分段。不过不再是基数,而是平方次数。

2.      乘法转加法:基于数组的矩阵使用,摒弃10n的实现。

 

现在单举整数为例。因为整数明白了,小数也只是多点细节的东西而已。

例如 9512312ACM题目上的第一个数。

 

首先,把12分解。为什么?(9512312 = ((951232 * 9512322 =951231+1+1+3+6 

目的很简单,就是构造尽可能多的2次方次数。至于为什么要构造2次方呢,是因为2次方下,乘数于被乘数相等,可以省许多工作(你只需要记得当前的次方数,和原本的1次方数,至少在这个算法看来是这样。)。

矩阵的应用,是对大大相乘的削减,取代为小乘小加。看图:

 95123
9814591827
5452551015
195123
21810246
32715369

95123  =   9048385129

乘法的本质是什么呢?加法?前一步。于是你发现了:

 95123
9814591827
5452551015
195123
21810246
32715369



 

9,是951232的个位数。

6+6,是951232的十位数,减去进位的10,也就是2

最后求出第一次的平方和。

 

这就是该算法的核心了。由此不断累积,得到更高阶的幂。往后的工作,也就是重复这种运算,实践这种思想。

 

该算法好不好?

以作者的身份来说,它的原理很坦白。而在时空复杂度的问题上,设计到大数组的操作,for循环的大量使用,时空复杂度应该不小,有待进一步优化。

(注:另外,short类型的最大值为32767,在最大斜线上32767/81=404 也就是说,最大支持的数不能大于999..94049)。)

 

 

后记:

很多时候吧,得出一个想法也许不是相像那么难。因为随着社会阅历的增加,更方面知识的扩展,只要注重积累,每个难题都有可能会找到它的原型。而也是很多时候,解决这些有想法的问题时,做起来可还挺费劲的。所以还真要多实践实践。(ps:多积累思想,多实践技术)

 

 

 

附上 实现源码(Java实现):

 

public class HighAccuracy {

 

   

   

    private byte n; // times of square

   

    short[] each // to store each short in inputNum

    private short dot = 0;  // original location of dot

   

   

    public HighAccuracy(String num, byte n){

       this.n = n;

       getOriginalList_From_InputNum(throwUselessZero(num));

    }

   

   

    public void showResult(){

       short[][] matrix = this.toGet_Matrix();

       short[] shorts = this.getMatrixToShortList(matrix);

 

       for(int index=0; index<shorts.length; index++){                             //检索 小数点dot 的位置

           if(index==0 && shorts[0] == 0){

              System.out.print(".");continue;

           }

           if(shorts[0]!=0 && index==(shorts.length-this.dot*this.n))

              System.out.print(".");

          

          

           System.out.print(shorts[index]);

       }

       System.out.println();

    }

   

   

    private String throwUselessZero(String inputNum){

       if(inputNum.charAt(inputNum.length()-1)=='0'){

           int i=0;

           while(inputNum.charAt(inputNum.length()-(++i))=='0');

           if(inputNum.charAt(inputNum.length()-(i+1))=='.') i++;

          

           return inputNum.substring(0, inputNum.length()-i+1);

       }

      

       return inputNum;

    }

   

    private void getOriginalList_From_InputNum(String inputNum){

       char[] eachChar = inputNum.toCharArray();

      

       if(inputNum.contains("."))

           each = new short[inputNum.length()-1];

       else

           each = new short[inputNum.length()];

      

       for(int i=0,j=0; i<inputNum.length(); i++){                      

           if(eachChar[i] != '.'){

              each[j++] = (short)(eachChar[i]-48);

           }else{

              dot = (short)((inputNum.length()-1) - i);             //to get the dot's location

           }

       }

    }

   

    private byte[] get_n_list(byte t){

       byte[] list = new byte[8];

       int i = 0;

       while( t>=1 ){

          

           if(t%2 == 1){

              list[i++] = 1;

              t-=1;

           }

           if((t = (byte)(t/2))== 1){

              list[i++] = 1;

              list[i] = 1;

           }else{

              if(t != 0)

                  list[i++] = t;

           }

       }

       return list;

    }

 

   

    private short[][] toGet_Matrix(){

      

       short[][] matrix = null;

       short[] previous = each;

       short[] current = each;

 

       byte[] nbytes = this.get_n_list(this.n);

      

       for(int i=nbytes.length-1; i>=0; i--){                   // 根据 前一矩阵和序列 当前矩阵和序列 得到 当前矩阵

                                                                //  previous 指向 当前矩阵 得出的求和序列

                                                         //  current 指向 下一个矩阵和序列, 根据 nbytes 得出

           if(nbytes[i] != 0){                                 //reach the end of nList

              if(nbytes[i+1]==0)i--;

             

              matrix = new short[previous.length][current.length];  System.out.println();                     

               for(int a=0; a<matrix.length; a++){

                 

                  for(int j=0;j<matrix[0].length;j++){

                     matrix[a][j] = (short)(previous[a]*current[j]);

                  }

              }

             

              if(i != 0){

                  previous = this.getMatrixToShortList(matrix);

                  if(nbytes[i-1] == 1){

                      current = each;

                  }else{

                     current = previous;

                  }

              }

           }

       }

       return matrix;

    }

 

   

    private short[] Once_Matrix_Sum(short[][] matrix_parameter){

       int matrix_x = matrix_parameter.length;

       int matrix_y = matrix_parameter[0].length;

      

       short[] matrix_sum = new short[matrix_x+matrix_y-1];

                                                                    // 各位(个十百千万...)求和: 矩阵 反斜 求和

                                                            // 大乘  小加 运算

       for(int index=0; index<matrix_sum.length ; index++){               

           matrix_sum[index] = 0;

           int moveStep_x = index+1;

           int moveStep_y = 1;

          

           int xx = matrix_x-moveStep_x;

           if(xx<0){

              xx=0;

              moveStep_y = index+2-matrix_x;

           }

          

           for( ; moveStep_y<=(index+1) && moveStep_y<=matrix_y; moveStep_x--,moveStep_y++ ){

              if(moveStep_x > 0){

                  matrix_sum[index] += matrix_parameter[xx++][matrix_y-moveStep_y];

              }

           }

       }     

       return matrix_sum;

    }

   

   

    private short[] getMatrixToShortList(short[][] matrix_parameter){                        // get the correct short list

      

       short[] matrix_sum = Once_Matrix_Sum(matrix_parameter);

      

       for(int i=0; i<matrix_sum.length-1; i++){                                    //最高位除外,其他位置 向上进位

           if(matrix_sum[i]>9){

              matrix_sum[i+1] += (short)((matrix_sum[i]/10));

              matrix_sum[i] = (short)((matrix_sum[i]));

           }

       }

       short[] matrix_sum_;

       int index;

       if(matrix_sum[matrix_sum.length-1] > 9){                                     // 判断最高位 是否有进位产生

           matrix_sum_ = new short[matrix_sum.length+1];                            //  由此 判断 创建的 short[] 数组是否长度+1

           matrix_sum_[0] = (short)(matrix_sum[matrix_sum.length-1]/10);

           matrix_sum_[1] = (short)(matrix_sum[matrix_sum.length-1]);

           index = 2;

          

       }else{

           matrix_sum_ = new short[matrix_sum.length];

           matrix_sum_[0] = matrix_sum[matrix_sum.length-1];

           index = 1;

       }

                                                                          // 等到 真正的求和序列

       for(int i=1; i<matrix_sum.length; i++,index++){

           matrix_sum_[index] = matrix_sum[matrix_sum.length-1-i];   

       }

   

       return matrix_sum_;

    }

 

   

   

    public static void main(String[] args) {

       // TODO Auto-generated method stub

      

       String numStr = "95.123";

       byte times = (byte)12;

       HighAccuracy ha = new HighAccuracy(numStr, times);

 

       ha.showResult();

    }

}

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值