Java 中 BigInteger 用法实践
Java 语言中,有 Integer 和 BigInteger 两种整型,
其中 Integer 类型的基本数据类型就是 int,占4个字节
本主要介绍Java中的 BigInteger类型的使用实践
BigInteger不是基本数据类型之一,它其实更像String、Integer,是Java里的一个类。
BigInteger的初始化方式却没有String那么方便可以直接赋值,而是跟其他自定义的类一样,要调用它的构造器进行初始化。这个类的取值范围原则上是没有上限的,取决于你的计算机的内存。
1. 赋值:
BigInteger a=new BigInteger("1"); // 字符
BigInteger b=BigInteger.valueOf(1); // 整型
2. 运算
① add(); 大整数相加
BigInteger a=new BigInteger(“23”);
BigInteger b=new BigInteger(“34”);
a. add(b);
②subtract(); 相减
③multiply(); 相乘
④divide(); 相除取整
⑤remainder(); 取余
⑥pow(); a.pow(b)=a^b
⑦gcd(); 最大公约数
⑧abs(); 绝对值
⑨negate(); 取反数
⑩mod(); a.mod(b)=a%b=a.remainder(b);
3. BigInteger构造函数
一般用到以下两种:
BigInteger(String val);
将指定字符串转换为十进制表示形式;
BigInteger(String val,int radix);
将指定基数的 BigInteger 的字符串表示形式转换为 BigInteger
4. 基本常量
A=BigInteger.ONE 1
B=BigInteger.TEN 10
C=BigInteger.ZERO 0
5. 比较
n.compareTo(BigInteger.ZERO)==0 // 相当于n==0
if(a[i].compareTo(n)>=0 && a[i].compareTo(m)< =0) // a[i]>=n && a[i]<=m
6. BigInteger 常用的方法
BigInteger abs() 返回大整数的绝对值 BigInteger add(BigInteger val) 返回两个大整数的和 BigInteger and(BigInteger val) 返回两个大整数的按位与的结果 BigInteger andNot(BigInteger val) 返回两个大整数与非的结果 BigInteger divide(BigInteger val) 返回两个大整数的商 double doubleValue() 返回大整数的double类型的值 float floatValue() 返回大整数的float类型的值 BigInteger gcd(BigInteger val) 返回大整数的最大公约数 int intValue() 返回大整数的整型值 long longValue() 返回大整数的long型值 BigInteger max(BigInteger val) 返回两个大整数的最大者 BigInteger min(BigInteger val) 返回两个大整数的最小者 BigInteger mod(BigInteger val) 用当前大整数对val求模 BigInteger multiply(BigInteger val) 返回两个大整数的积 BigInteger negate() 返回当前大整数的相反数 BigInteger not() 返回当前大整数的非 BigInteger or(BigInteger val) 返回两个大整数的按位或 BigInteger pow(int exponent) 返回当前大整数的exponent次方 BigInteger remainder(BigInteger val) 返回当前大整数除以val的余数 BigInteger leftShift(int n) 将当前大整数左移n位后返回 BigInteger rightShift(int n) 将当前大整数右移n位后返回 BigInteger subtract(BigInteger val)返回两个大整数相减的结果 byte[] toByteArray(BigInteger val)将大整数转换成二进制反码保存在byte数组中 String toString() 将当前大整数转换成十进制的字符串形式 BigInteger xor(BigInteger val) 返回两个大整数的异或
使用实践1
import java.math.BigInteger; import java.util.Scanner; public class Main { public static void main(String[] args) { // BigInteger 需引入 import java.math.BigInteger; BigInteger sum = new BigInteger("1"); Scanner input = new Scanner(System.in); while(true) { BigInteger num = input.nextBigInteger(); if(num .equals(BigInteger.ZERO ) ) break; else sum = sum.multiply(num); } int cnt = 0; System.out.println(sum); while(true ) { BigInteger[] bis = sum.divideAndRemainder(BigInteger.TEN); if(bis[1].equals(BigInteger.ZERO)) { cnt++; sum = bis[0]; } else { break; } } System.out.println(cnt); } }
使用实践2:
使用场景,请见米扑博客:LeetCode 2. 两链表整数相加生成一个和的新链表
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ import java.math.BigInteger; class Solution { // 链表转BigInteger整型,求和计算,再将BigInteger转成结果链表 public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode result = new ListNode(-1); // 结果头结点(额外多建的一个节点) ListNode curr = result; // 当前节点, 不断的添加节点并移动 BigInteger bigInt1 = new BigInteger("0"); // BigInteger 需引入java包 import java.math.BigInteger; BigInteger bigInt2 = new BigInteger("0"); // 1.1 链表list1转成整型数, 例如逆序 2->4->3 转成 342 int count = 0; while(l1 != null) { // int num = Integer.valueOf(l1.val + "").intValue(); // str to Integer // int num2 = Integer.parseInt(l1.val + ""); // str to Integer BigInteger listVal1 = BigInteger.valueOf(l1.val); // int to BigInteger if(count == 0) { bigInt1 = listVal1; } else { int intPow = new Double(Math.pow(10, count)).intValue(); // double to int, 100.000000 -> 100 BigInteger bigPow = BigInteger.valueOf(intPow); // int to BigInteger bigInt1 = bigInt1.add( listVal1.multiply(bigPow) ); // bigInt + bigInt } System.out.printf("\n count: %d , listVal1: %s , bigInt1: %s", count, listVal1.toString(), bigInt1.toString()); count++; l1 = l1.next; } // 1.2 链表list1转成整型数, 例如逆序 5->6->4 转成 465 count = 0; while(l2 != null) { BigInteger listVal2 = BigInteger.valueOf(l2.val); // int to BigInteger if(count == 0) { bigInt2 = listVal2; } else { int intPow = new Double(Math.pow(10, count)).intValue(); BigInteger bigPow = BigInteger.valueOf(intPow); bigInt2 = bigInt2.add( listVal2.multiply(bigPow) ); } System.out.printf("\n count: %d , listVal12: %s , bigInt2: %s", count, listVal2.toString(), bigInt2.toString()); count++; l2 = l2.next; } // 2. 两个链表转成的整型相加 342 + 465 = 807 BigInteger bigSum = bigInt1.add(bigInt2); System.out.printf("\n%s + %s = %s", bigInt1.toString(), bigInt2.toString(), bigSum.toString()); // 3. 最后把整型结果转成链表, 例如 807 to 7->0->8 do { BigInteger lowNum = bigSum.mod(BigInteger.valueOf(10)); bigSum = bigSum.divide(BigInteger.valueOf(10)); ListNode node = new ListNode(lowNum.intValue()); // bigInt to int curr.next = node; curr = node; } while(bigSum.compareTo(BigInteger.valueOf(0)) > 0); return result.next; } /* 运行结果,不出意外,报错了 测试用例: l1 = [2,4,3], l2 = [5,6,4] 成功 测试用例: l1 = [0], l2 = [0] 成功 测试用例: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] 成功 测试用例: l1 = [1,1,1,1,1,1,1,1,1,1,1], l2 = [1,1,1,1,1,1,1,1,1,1,1] 失败 预期结果: [2,2,2,2,2,2,2,2,2,2,2] 实际输出: [6,1,5,9,8,1,7,1,5,6] 大数溢出了, BigInteger整数部分精度最大支持10位, 即 2^32 = 4294967296 详细调试日志如下: count: 0 , listVal1: 1 , bigInt1: 1 count: 1 , listVal1: 1 , bigInt1: 11 count: 2 , listVal1: 1 , bigInt1: 111 count: 3 , listVal1: 1 , bigInt1: 1111 count: 4 , listVal1: 1 , bigInt1: 11111 count: 5 , listVal1: 1 , bigInt1: 111111 count: 6 , listVal1: 1 , bigInt1: 1111111 count: 7 , listVal1: 1 , bigInt1: 11111111 count: 8 , listVal1: 1 , bigInt1: 111111111 count: 9 , listVal1: 1 , bigInt1: 1111111111 count: 10 , listVal1: 1 , bigInt1: 3258594758 count: 0 , listVal12: 1 , bigInt2: 1 count: 1 , listVal12: 1 , bigInt2: 11 count: 2 , listVal12: 1 , bigInt2: 111 count: 3 , listVal12: 1 , bigInt2: 1111 count: 4 , listVal12: 1 , bigInt2: 11111 count: 5 , listVal12: 1 , bigInt2: 111111 count: 6 , listVal12: 1 , bigInt2: 1111111 count: 7 , listVal12: 1 , bigInt2: 11111111 count: 8 , listVal12: 1 , bigInt2: 111111111 count: 9 , listVal12: 1 , bigInt2: 1111111111 count: 10 , listVal12: 1 , bigInt2: 3258594758 3258594758 + 3258594758 = 6517189516 */
知识拓展
Java 中 String 和 int 互相转化
1 字串 String 转换成整数 int
方法1)
int i = Integer.parseInt([String]);
或
int i = Integer.parseInt([String],[int radix]);
方法2)
int i = Integer.valueOf(my_str).intValue();
注: 字串转成 Double, Float, Long 的方法大同小异.
2 整数 int 转换成字串 String
方法1) String s = String.valueOf(i);
方法2) String s = Integer.toString(i);
方法3) String s = "" + i;
注: Double, Float, Long 转成字串的方法大同小异.
int -> String
int i=12345;
String s="";
第一种方法:s=i+"";
第二种方法:s=String.valueOf(i);
这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢?
String -> int
s="12345";
int i;
第一种方法:i=Integer.parseInt(s);
第二种方法:i=Integer.valueOf(s).intValue();
这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢?
以下是答案:
第一种方法:s=i+""; //会产生两个String对象
第二种方法:s=String.valueOf(i); //直接使用String类的静态方法,只产生一个对象
第一种方法:i=Integer.parseInt(s);//直接使用静态方法,不会产生多余的对象,但会抛出异常
第二种方法:i=Integer.valueOf(s).intValue();//Integer.valueOf(s) 相当于 new Integer(Integer.parseInt(s)),也会抛异常,但会多产生一个对象
Java字符串格式化 String.format()的使用
String类的format()方法用于创建格式化的字符串以及连接多个字符串对象。熟悉C语言的同学应该记得C语言的sprintf()方法,两者有类似之处。format()方法有两种重载形式。
format(String format, Object... args) 新字符串使用本地语言环境,制定字符串格式和参数生成格式化的新字符串。
format(Locale locale, String format, Object... args) 使用指定的语言环境,制定字符串格式和参数生成格式化的字符串。
显示不同转换符实现不同数据类型到字符串的转换,如图所示。
转 换 符 | 说明 | 示例 |
%s | 字符串类型 | "mingrisoft" |
%c | 字符类型 | 'm' |
%b | 布尔类型 | true |
%d | 整数类型(十进制) | 99 |
%x | 整数类型(十六进制) | FF |
%o | 整数类型(八进制) | 77 |
%f | 浮点类型 | 99.99 |
%a | 十六进制浮点类型 | FF.35AE |
%e | 指数类型 | 9.38e+5 |
%g | 通用浮点类型(f和e类型中较短的) | |
%h | 散列码 | |
%% | 百分比类型 | % |
%n | 换行符 | |
%tx | 日期与时间类型(x代表不同的日期与时间转换符 |
测试用例如下:
public static void main(String[] args) { String str=null; str=String.format("Hi,%s", "王力"); System.out.println(str); str=String.format("Hi,%s:%s.%s", "王南","王力","王张"); System.out.println(str); System.out.printf("字母a的大写是:%c %n", 'A'); System.out.printf("3>7的结果是:%b %n", 3>7); System.out.printf("100的一半是:%d %n", 100/2); System.out.printf("100的16进制数是:%x %n", 100); System.out.printf("100的8进制数是:%o %n", 100); System.out.printf("50元的书打8.5折扣是:%f 元%n", 50*0.85); System.out.printf("上面价格的16进制数是:%a %n", 50*0.85); System.out.printf("上面价格的指数表示:%e %n", 50*0.85); System.out.printf("上面价格的指数和浮点数结果的长度较短的是:%g %n", 50*0.85); System.out.printf("上面的折扣是%d%% %n", 85); System.out.printf("字母A的散列码是:%h %n", 'A'); } /* 运行结果如下: Hi,王力 Hi,王南:王力.王张 字母a的大写是:A 3>7的结果是:false 100的一半是:50 100的16进制数是:64 100的8进制数是:144 50元的书打8.5折扣是:42.500000 元 上面价格的16进制数是:0x1.54p5 上面价格的指数表示:4.250000e+01 上面价格的指数和浮点数结果的长度较短的是:42.5000 上面的折扣是85% 字母A的散列码是:41 */
数据类型在16位、32位和64位系统下所占字节
编写C、C++程序时需要考虑每种数据类型在内存中所占的内存大小,
即使同一种数据类型在不同平台下所占内存大小亦不相同,
具体对比如下:
数据类型 | 16位系统(byte) | 32位系统(byte) | 64位系统(byte) |
char | 1 | 1 | 1 |
short 、unsigned short | 2 | 2 | 2 |
int、unsigned int | 2 | 4 | 4 |
long、unsigned long | 4 | 4 | 8 |
float | 4 | 4 | 4 |
double | 8 | 8 | 8 |
long long | 8 | 8 | 8 |
long double | 10/12 | 10/16 | |
指针 | 2 | 4 | 8 |
说明:
long double 有效位10字节。32位为了对齐实际分配12字节;64位分配16字节
64 位的优点:应用程序可以直接访问 4EB 的内存和文件大小最大达到4 EB(2 的 63 次幂);可以访问大型数据库。
参考推荐:
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2021-03-09 05:45:56
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!