高精度运算

向英雄致敬,向逝者致哀 愿逝者安息,生者奋发 愿国泰民安,山河无恙

前言

在写Java代码时候,我们其实很少去考虑高精度运算,即使遇到无法避免高精度的计算问题也不会太烦恼,因为有大整数类BigInteger以及BigDecimal工具使用。

但是抛开Java不说,像自己之前在为一家银行计算员工工资的时候,自己还是使用JS去处理计算然后做页面展示的,但是因为银行系统 引入包是比较费劲的,所以当时自己第一次将高精度运算运用到工作中,之后由于使用Java越来越多,对于手撸高精度计算代码也就越来越少了。但是直到过年在家使用C++刷PAT算法的时候,又不可避免的使用到高精度算法(因为long int和long long也无法解决整数长度受限的问题), 所以今天得空用Java来实现高精度的运算(嗯.....有没有意义不知道,反正闲着也是闲着),除法就先放一放,因为高精度除高精度有点难,这里就谈一谈高精度的加减乘。先看一下效果图(上方结果使用BigInteger的方法,下方结果自定义实现)

正文

高精度加

高精度的加法是比较容易理解的和实现,我们只需要注意进位就好, 将输入整数的字符串,进行遍历,将char类型转为int进行相加,保存进位在下一轮循环中使用即可。

    private static void add(String a, String b) {
        System.out.println("加===");
        BigInteger ba = new BigInteger(a);
        BigInteger bb = new BigInteger(b);
        System.out.println("结果=" + ba.add(bb));
        String res = "";
        int temp;
        int adv = 0;
        for (int i = a.length() - 1, j = b.length() - 1; i > -1 || j > -1; ) {
            if (i > -1 && j > -1)
                temp = (a.charAt(i--) - '0') + (b.charAt(j--) - '0');
            else if (i > -1)
                temp = (a.charAt(i--) - '0');
            else
                temp = (b.charAt(j--) - '0');
            temp += adv;
            adv = temp / 10;
            res = temp % 10 + res;
        }
        if (adv != 0) {
            res = adv + res;
        }
        System.out.println("结果=" + res);
    }

高精度减法

高精度减法和加法比较,稍微复杂一些,因为在减法中,需要根据输入数字的相对大小来判断是否输出负号,还需要注意是否要"借位",以及对于结果进行高位去0

    private static void sub(String a, String b) {
        System.out.println("减===");
        BigInteger ba = new BigInteger(a);
        BigInteger bb = new BigInteger(b);
        System.out.println("结果=" + ba.subtract(bb));
        String res = "";
        int temp;
        int sub = 0;
        String ch = "";
        if (a.length() < b.length() || (a.compareTo(b) < 0)) {//正数
            String c = a;
            a = b;
            b = c;
            ch = "-";
        }
        for (int i = a.length() - 1, j = b.length() - 1; i > -1 || j > -1; ) {
            if (i > -1 && j > -1) {
                int tempA = a.charAt(i--) - '0' + sub;
                sub = 0;
                int tempB = b.charAt(j--) - '0';
                if (tempA < tempB) {
                    sub = -1;
                    temp = tempA + 10 - tempB;
                } else {
                    temp = tempA - tempB;
                }
            } else if (i > -1) {
                temp = (a.charAt(i--) - '0') + sub;
                sub = 0;
            } else {
                temp = (b.charAt(j--) - '0') + sub;
                sub = 0;
            }

            res = temp + res;
        }
        //高位去0
        int spilt = 0;
        for (int i = 0; i < res.length(); i++) {
            if (res.charAt(i) - '0' != 0) {
                break;
            } else {
                spilt++;
            }
        }
        res = res.substring(spilt);
        System.out.println("结果=" + ch + res);
    }

高精度乘法

乘法和加法类似,但是因为涉及到累计相加的过程(模拟算术做竖式乘法的过程),所以结合数组更加方便理解一些

    private static void multiply(String a, String b) {
        System.out.println("乘法===");
        BigInteger ba = new BigInteger(a);
        BigInteger bb = new BigInteger(b);
        System.out.println("结果=" + ba.multiply(bb));
        int as[] = new int[a.length()];
        int bs[] = new int[b.length()];
        for (int i = 0; i < a.length(); i++) {
            as[i] = a.charAt(a.length() - i - 1) - '0';
        }

        for (int i = 0; i < b.length(); i++) {
            bs[i] = b.charAt(b.length() - i - 1) - '0';
        }
        int res[] = new int[b.length() + a.length()];

        for (int i = 0; i < a.length(); i++) {
            int adv = 0;
            int j;
            for (j = 0; j < b.length(); j++) {
                res[i + j] = as[i] * bs[j] + adv + res[i + j];
                adv = res[i + j] / 10;
                res[i + j] = res[i + j] % 10;
            }
            res[i + j] = adv;
        }
        int len = a.length() + b.length() - 1;
        if (res[len] == 0) len--;
        System.out.printf("结果=");
        for (int i = len; i >= 0; i--) {
            System.out.printf(res[i] + "");
        }
    }

主函数:

public class Test {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("输入a");
        String a = "";
        if (scanner.hasNext())
            a = scanner.next();
        System.out.println("输入b");
        String b = "";
        if (scanner.hasNext())
            b = scanner.next();
        add(a, b);
        sub(a, b);
        multiply(a, b);
    }

}

本文分享自微信公众号 - 每天学Java(gh_fddfb9d03324),作者:每天学Java

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Security:安全访问控制

    “ 在前面的两篇文章中,说了如何使用Spring Boot搭建Security项目以及实现自定义登录认证,今天就拿一个具体的前后端分离项目来看一下安全访问的控制...

    每天学Java
  • 关于CAS实现单点登录(一)

    单点登录:Single Sign On,简称SSO,SSO使得在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    每天学Java
  • Spring AOP的简单应用

    “ 在各种业务场景中,我们可会有打印日志这种语句,通常为了方便我们直接写在业务逻辑的代码中。实际上和业务无关的代码我们也放入到业务逻辑中,会带来了较强的侵入性编...

    每天学Java
  • Android实现微博菜单弹出效果

    先上Android仿微博菜单弹出效果图,这个截图不是很流畅,大家可以下载apk试一下。

    砸漏
  • Android ListView侧滑删除

      今天是个值得纪念的日子,今天点亮了博客专家!相信我是第一个粉丝数量在20位以下,排名在万级别的以外的博客专家。

    黄林晴
  • 自定义Androidk全量更新组件

      自动更新功能对于一个APP来说是必备的功能,特别是对于未投放市场下载的APP,每次都让用户删掉原来的,再下载新的版本,肯定是不合适的。

    饮水思源为名
  • 前缀树问题-LeetCode 409、412、414、415、419、421

    给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。 在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。 注意:...

    算法工程师之路
  • leetcode: 96. Unique Binary Search Trees

    JNingWei
  • 自定义 Behavior,实现嵌套滑动、平滑切换周月视图的日历

    使用 CoordinateLayout 可以协调它的子布局,实现滑动效果的联动,它的滑动效果由 Behavior 实现。以前用过小米日历,对它滑动平滑切换日月视...

    CCCruch
  • 《了不起的 nodejs》中 TwitterWeb 案例 bug 解决

    了不起的nodejs算是一本不错的入门书,不过书中个别案例存在bug,按照书中源码无法做出和书中相同效果,原本兴奋的心情掺杂着些许失落。 现在我们看一下第七章H...

    叙帝利

扫码关注云+社区

领取腾讯云代金券