zoukankan      html  css  js  c++  java
  • 当简单的计算遇上了大数,其实大数运算也很简单

    一、说三道四

       用代码实现简单的加减乘除运算会不会?只要你是个coder,我想这个答案都是肯定的吧!

    但是,今天我想说的是,当我们的运算遇到了大数,用原本的int、long、float、double数值类型

    都无法表示出来的时候,你们想过该如果解决这一类型的问题了吗?

      在这,你们可以先不用看卤煮撸的代码,想想如果自己遇到这个问题,该如果解决,也许你的想法

    很新颖,思路以及在算法的实现上更清晰。希望能够在广大的博友的集思广益下,大数的运算能够有

    一套更好的解决方案。不说了,咱们先撸代码吧。毕竟这才是主题!!!

    二、大数运算之加法运算

    package com.linjm.work;
    
    public class Add {
    
        public String forAdd(String p, String q) {
            String x = p;
            String y = q;
            
            int len = 0;
            String res = "";
            
            len = (x.length() > y.length()) ? x.length() : y.length();
            
            
            if (len == x.length())    y = Tools.fillZero(y, x.length() - y.length());
            if (len == y.length())    x = Tools.fillZero(x, y.length() - x.length());
            
            x = Tools.reverse(x);
            y = Tools.reverse(y);
            
            //m,n用于循环遍历时截取字符串x,y的每一位
            //flag用于标识m和n的每一次相加是否需要进位
            int m, n, flag = 0;
            
            //遍历x、y,对应位相加
            for (int i = 0; i < len; i++) {
                int sum;
                
                m = Integer.parseInt(x.substring(i, i + 1));
                n = Integer.parseInt(y.substring(i, i + 1));
                sum = m + n;
                
                if (flag == 1) {    
                    sum = sum + 1;
                    flag = 0;
                }
                
                if (sum >= 10) {
                    flag = 1;
                    sum = sum - 10;
                }
                
                res += sum;
            }
            
            if (flag == 1)    //最高位相加后还大于10,则须进位
                res += "1";
            
            return Tools.reverse(res);
        }
        
        
        
        public static void main(String[] args) {
            Add add = new Add();
            System.out.println(add.forAdd("555555555555555555", "5555555555555555551"));
        }
    }
    大数相加

     思路分析:

      大数的相加主要是通过字符串的相加来实现的。两个大数相加,找出位数较大的那个大数获取对应的长度,

    然后对较小的那个数进行左补0直至长度和较大的那个数的位数一样,最后循环累加两个大数的每一位的数值,

    遇到需要进位的需要设一个标识位标识。

    三、大数运算之减法运算

    package com.linjm.work;
    
    public class Sub {
        
        public String forSub(String p, String q) {
            String x = p;
            String y = q;
            
            int len = 0;
            String res = "";
            
            int sign = 0;    //0: x >= y、1: x < y 
            sign = Tools.forMax(x, y) ? 0 : 1;
            
            if (sign == 1) {
                x = q;
                y = p;
            }
            
            len = x.length();
            
            y = Tools.fillZero(y, x.length() - y.length());
            
            int m, n, flag = 0, num = 0;    //num标识出现0的次数,防止结果中高位出现多个0的情况
            
            for (int i = len; i > 0; i--) {
                int dif;
                
                m = Integer.parseInt(x.substring(i - 1, i));
                n = Integer.parseInt(y.substring(i - 1, i));
                
                dif = m - n;
                
                //标志位如果等于1,说明存在借位
                if (flag == 1) {
                    dif = dif - 1;
                    flag = 0;    //重置标志位
                }
                
                //判断是否需要借位
                if (dif < 0) {
                    flag = 1;    //标记
                    dif = dif + 10;
                }
                
                if (dif == 0) {
                    num ++;
                } else {
                    num = 0;
                }
                
                res += dif;
            }
            
            if (Tools.isZero(res))
                return "0";
    
            if (num > 0) {
                res = res.substring(0, res.length() - num);    //截取掉高位出现的连续num个0
            }
            
            return (sign == 1) ? "-" + Tools.reverse(res) : Tools.reverse(res);
        }
        
        
        
        public static void main(String[] args) {
            Sub sub = new Sub();
            System.out.println(sub.forSub("100000000", "1"));
        }
    }
    大数相减

      思路分析:

      大数相减在实现上和大数相加异曲同工,也是通过循环遍历大数的每一位,对其进行数值相减,在遇到需要借位的数值,

    设立一个标识位进行标识。当遇到被减数比减数小的时候,先用减数减去被减数,用标识位标识被减数比减数小,最后结果

    根据标识变量判断是否需要在结果上加上"-"。

    四、大数运算之乘法运算

    package com.linjm.work;
    
    public class Mul {
    
        public String forMul(String p, String q) {
            String x = Tools.maxNum(p, q);
            String y = Tools.minNum(p, q);
            
            if (y.length() > 15) {
                return "ERROR:两位数中必须有一个数的长度要小于15";
            }
                
            String sum = "0";
            
            Add add = new Add();
            Sub sub = new Sub();
            
            while (Long.parseLong(y) > 0) {
                sum = add.forAdd(sum, x);
                y = sub.forSub(y, "1");
            }
            
            return sum;
        }
        
        
        
        public static void main(String[] args) {
            Mul mul = new Mul();
            System.out.println(mul.forMul("1000", "20000"));
        }
    }
    大数相乘

     思路分析:

       大数相乘在算法的实现上个人表示有点不太满意,虽然实现了功能,但还是觉得代码的实现上和思路都很挫。

    乘法的最终思路就是多个数值的加法运算。所以大数的乘法就是多个大数的加法运算。但是遇到两个数值都是大数的情况下,

    运行速度会非常的慢。

    五、大数运算之除法运算

    package com.linjm.work;
    
    public class Div {
    
        public String forDiv (String p, String q) {
            String x = p;
            String y = q;
            
            String res = "0";
            String remain = "0";    //余数
            
            if (!Tools.forMax(x, y)) {
                return x + "的值要大等于" + y; 
            }
            
            Add add = new Add();
            Sub sub = new Sub();
            
            while (true) {
                x = sub.forSub(x, y);
                res = add.forAdd(res, "1");
                
                if (!Tools.forMax(x, y)) {
                    remain = x;
                    break;
                }
            }
            
            if (!Tools.isZero(remain))
                res = res + "……" +remain;
            
            return res;
        }
        
        
        
        public static void main(String[] args) {
            Div div = new Div();
            System.out.println(div.forDiv("222222222222222222222", "222222222222222222221"));
        }
    }
    大数相除

      思路分析:

      除法运算的实质也就是减法,让被除数一直减去除数,直到减不动了为止,统计下减了多少次除数,这个值就是商咯。

    但是存在的问题还是和大数的乘法是一样的,有待优化。

    六、大数运算之工具类

    package com.linjm.work;
    
    public class Tools {
    
        /**
         * @param s num
         * @Desc 字符串左补num个0
         * @return String
         * */
        public static String fillZero(String s, int num) {
            String res = "";
            
            for (int i = 0; i < num; i++) {
                res += "0";
            }
            
            return res + s;
        }
        
        /**
         * @param s
         * @Desc 反转字符串
         * @return String
         * */
        public static String reverse(String s) {
            String res = "";
            
            for (int i = s.length(); i > 0 ; i--) {
                res +=  s.substring(i - 1, i);
            }
            
            return res;
        }
        
        /**
         * @param x n(n最小值为1)
         * @Desc 获取字符串的n个字符
         * @return int
         * */
        public static int numAt(String x, int n) {
            return Integer.parseInt(x.substring(n - 1, n));
        }
        
        
        /**
         * @param x y
         * @Desc 获取两个大数中较大的数
         *     注:此方法不对两个数是否是数字进行校验
         * @return String
         * */
        public static String maxNum(String x, String y) {
            String max = "";
            
            if (x.length() > y.length()) {
                max = x;
            } else if (x.length() == y.length()) {
                for (int i = 1; i <= x.length(); i++) {
                    if (numAt(x, i) != numAt(y, i)) {
                        max = (numAt(x, i) > numAt(y, i)) ? x : y;
                    } else if (i == x.length()) {
                        max = x;
                    }
                }
            } else if (x.length() < y.length()) {
                max = y;
            } else {
                return "ERROR";
            }
            return max;
        }
        
        
        /**
         * @param x y
         * @Desc 获取两个大数中较小的数
         *     注:此方法不对两个数是否是数字进行校验
         * @return String
         * */
        public static String minNum(String x, String y) {
            String min = "";
            
            if (x.length() > y.length()) {
                min = y;
            } else if (x.length() == y.length()) {
                for (int i = 1; i <= x.length(); i++) {
                    if (numAt(x, i) != numAt(y, i)) {
                        min = (numAt(x, i) > numAt(y, i)) ? y : x;
                    } else if (i == x.length()) {
                        min = x;
                    }
                }
            } else if (x.length() < y.length()) {
                min = x;
            } else {
                return "ERROR";
            }
            return min;
        }
        
        
        /**
         * @param x y
         * @Desc 大数x是否大于大数y
         * @return true/false
         * */
        public static boolean forMax(String x, String y) {
            if (x.length() > y.length()) {
                return true;
            } else if (x.length() == y.length()) {
                for (int i = 1; i <= x.length(); i++) {
                    if (numAt(x, i) != numAt(y, i)) {
                        return (numAt(x, i) > numAt(y, i)) ? true : false;
                    } else if (i == x.length()) {
                        return true;
                    }
                }
            } else if (x.length() < y.length()) {
                return false;
            } else {
                System.out.println("ERROR!!!");
            }
            return false;
        }
        
        
        
        /**
         * @param x
         * @Desc 判断x是否是0或000……
         * @return true/false
         * */
        public static boolean isZero(String x) {
            boolean flag = true;
            
            for (int i = 1; i <= x.length(); i++) {
                if (Tools.numAt(x, i) != 0) {
                    return false;
                }
            }
            
            return flag;
        }
        
    }
    工具类

      

    七、卤煮有话说

       也许撸主的代码算法的实现上可能会多多少少存在点瑕疵,第一遍写出来的代码不是最好的,但我们要尽我们所能去

    优化和改善我们的代码。大家有什么想法都可以说出来,我们一起来探讨大数的加减乘除,让这么有意义的事可以得到

    最优质的解决方案。在求知的路上,我们不怕批评,不怕失败,更不要在意别人的嘲笑,一步一步攀岩,我们终将登顶。

      想是一回事,做又是另一回事。让我们脑洞大开,集思广益一起来探讨吧!!!

      如果你觉得博文写的不错,就点下【推荐一下】或【打赏卤煮一杯奶茶吧!!!

  • 相关阅读:
    什么是 bean 的自动装配?
    什么是 Spring 的内部 bean?
    什么是 Spring 的 MVC 框架?
    Spring AOP and AspectJ AOP 有什么区别?
    解释 JDBC 抽象和 DAO 模块?
    volatile 类型变量提供什么保证?
    一个 Spring Bean 定义 包含什么?
    什么是 Spring MVC 框架的控制器?
    使用 Spring 访问 Hibernate 的方法有哪些?
    什么是 Callable 和 Future?
  • 原文地址:https://www.cnblogs.com/JimLy-BUG/p/5965487.html
Copyright © 2011-2022 走看看