也许,你很少会遇见这样的计算,当你要计算的值,超过了最大long能表数的范围后,怎么办?本文提供一种比较愚笨的办法,有比这更好的算法,希望贴出来!
原理是,按字符串来处理,如果2个数相加的和<0的时候,说明已经超过了long的最大表数范围,所以按字符串处理,如果不小于0则按long计算!(因为long的最大表数+1为负数)计算的时候按18位截取字符串,因为long的10进制最大表数位数是19位,所以两个18位的最大值相加也还是long类型表数范围内,也即最大位数不会超过19位,而且从左往右数的第一位永远是1,也即进位,不会溢出!比如9+9=18,2个1位数相加,就拿最大值相加也是18,最多也就是2位,而且从左往右第一位永远不会大于1,所以,如果2个一位数相加的结果是2位,那么保留个位数,十位数作为进位,继续相加!
废话不多说,直接看代码,注释就不写那么多了,没那么复杂,debug一次就明了!
package cn.com;
public class BigNumber {
private final static int threshold = 18;
public static void main(String[] args) {
long l1 = 444L;
long l2 = 5555L;
long l3 = 9223372036854775807L;
long l4 = 1L; //5555555555555555555
long l5 = 555555555555555555L; //5555555555555555555
//1111111111111111110
//11111111111111111110
System.out.println(String.valueOf(l5).length());
// l3 = l4;
String value = add(l1,l2);
System.out.println(value);
long s = System.currentTimeMillis();
value = add(l3,l4);
long e = System.currentTimeMillis();
System.out.println("consuming times :"+(e-s));
System.out.println("string value = "+value+", and length = "+String.valueOf(value).length());
System.out.println("string value = "+Long.MAX_VALUE+", and length = "+String.valueOf(value).length());
System.out.println("long value = "+(l3+l4));
}
public static String summation(String s1 , String s2){
int len1 = s1.length();
int len2 = s2.length();
int maxlen = len1>len2?len1:len2;
int minlen = len1<len2?len1:len2;
StringBuffer pre0 = new StringBuffer();
for(int i=0; i<maxlen-minlen; i++){
pre0.append(0);
}
if(len1 < len2){
s1 = pre0.toString()+s1;
}else{
s2 = pre0.toString()+s2;
}
String temp = "";
int carry = 0;//进位
String[] ss1 = null;
String[] ss2 = null;
if(maxlen > threshold){
ss1 = group(s1,maxlen);
ss2 = group(s2,maxlen);
}else{
ss1 = new String[]{s1,""};
ss2 = new String[]{s2,""};
}
for(int i = ss1.length-1; i>=0; i--){
String temp_str = parseString(ss1[i],ss2[i],carry);
if(temp_str.length() > threshold){
temp = temp_str.substring(1,temp_str.length()) + temp;
carry = 1;
}else{
if(temp_str.length() > ss1[i].length()){
temp = temp_str.substring(1,temp_str.length()) + temp;
carry = 1;
}else{
temp = temp_str + temp;
carry = 0;
}
}
}
if(carry != 0){
temp = carry + temp;
}
return temp;
}
public static String add(String s1, String s2){
long l1;
long l2;
try{
l1 = Long.parseLong(s1);
l2 = Long.parseLong(s2);
if(l1+l2 < 0){
return summation(s1, s2);
}else{
return String.valueOf(l1+l2);
}
}catch(NumberFormatException e){
return summation(s1, s2);
}
}
//根据给定的两个long类型的数值,相加后,得到字符串结果,如果结果的长度大于19,说明已经超过了long的最大表数
public static String add(long l1 , long l2){
if(l1 + l2 <0){
return summation(String.valueOf(l1), String.valueOf(l2));
}else{
return String.valueOf(l1+l2);
}
}
private static String parseString(String s1,String s2,int i){
long l1 = 0;
long l2 = 0;
if(s1!=null && !s1.equals("")){
l1 = Long.parseLong(s1);
}
if(s2!=null && !s2.equals("")){
l2 = Long.parseLong(s2);
}
return (l1+l2+i>0) ? (String.valueOf(l1+l2+i)) : "";
}
private static String[] group(String s,int len){
String[] ss = new String[(len/threshold)+1];
for (int i = 0; i <= len/threshold; i++) {
if(i==len/threshold)
ss[i] = s.substring(i*threshold,len);
else
ss[i] = s.substring(i*threshold,i*threshold+threshold);
}
return ss;
}
}
方法里边首先会判断,是否超过了long的表数范围,如果超过才会按字符串处理,否则按long处理
======================================
下面是完善的,长度小的字符串不补0的方法
package com.chinamobile.omae.appmaster.schedule.util;
import java.util.regex.Pattern;
public class BigNumCal {
private final static int threshold = 18;
private final static Pattern pattern = Pattern.compile("\\D");
public static void main(String[] args) {
String s1 = "a1234";
String s2 = "888888888888888888888888888888888888888888888888888888";
add(s1,s2);
}
// 字符串加法运算
private static String summation(String s1, String s2) {
int len1 = s1.length();
int len2 = s2.length();
int maxlen;
String maxStr = null;
String minStr = null;
if(len1>len2){
maxlen = len1;
maxStr = s1;
minStr = s2;
}else{
maxlen = len2;
maxStr = s2;
minStr = s1;
}
String temp = "";
int carry = 0;// 进位
String[] maxs = null;
String[] mins = null;
if (maxlen > threshold) {
maxs = group(maxStr, maxlen);
mins = group(minStr, maxlen);
} else {
maxs = new String[] { s1, "" };
mins = new String[] { s2, "" };
}
//长度长的字符串分组后的长度,以这个长度为标准来进行循环计算
//这里为了避免两个数组大小不等而引发的数组越界异常,单独写了一个方法,获取数组中的字符串getString()方法
int mins_len = mins.length;
String max_str = null;
String min_str = "";
for (int i = maxs.length - 1; i >= 0; i--) {
max_str = getString(maxs,i);
if(mins_len >= 0)
min_str = getString(mins,mins_len-1);
else
min_str = "";
String temp_str = parseString(max_str, min_str, carry);
if(mins_len>=0)
mins_len--;
//如果大于阈值,则进位置为1,截取阈值范围内的字符串(从第一位截取,第0位是进位)并保留,不再做运算
if (temp_str.length() > threshold) {
temp = temp_str.substring(1, temp_str.length()) + temp;
carry = 1;
} else {//如果小于阈值,但是结果的长度大于最大字符串数组某下标的长度,也进1,比如8+8=16,结果是16,2位数,大于1位数,所以也需要进1
if (temp_str.length() > maxs[i].length()) {
temp = temp_str.substring(1, temp_str.length()) + temp;
carry = 1;
} else {
temp = temp_str + temp;
carry = 0;
}
}
}
if (carry != 0) //如果不为0则加上,否则就别加了,因为进位为0加上的话结果是"08787XXXX",开头是0,不好看
temp = carry + temp;
return temp;
}
// 根据给定的两个String类型的数值,相加后,得到字符串结果,如果结果的长度大于19,说明已经超过了long的最大表数
// 会自动判断传进来的字符串是否超过了long的最大表数范围,并判断2个字符串转换为long类型后的和是否超过long的表数范围,如果没超过,则进行long运算,否则进行字符串运算
public static String add(String s1, String s2) {
if(pattern.matcher(s1).find() || pattern.matcher(s2).find())
throw new IllegalArgumentException("Illegal type of String ["+s1+"],must be number of String");
long l1;
long l2;
try {
l1 = Long.parseLong(s1);
l2 = Long.parseLong(s2);
if (l1 + l2 < 0)
return summation(s1, s2);
else
return String.valueOf(l1 + l2);
} catch (NumberFormatException e) {//如果捕获到格式化异常则说明溢出了,按字符串处理
return summation(s1, s2);
}
}
// 根据给定的两个long类型的数值,相加后,得到字符串结果,如果结果的长度大于19,说明已经超过了long的最大表数
// 自动判断传入的long值,相加的和是否小于0,如果小于则超过了long的最大表数范围,用字符串处理E172629180
public static String add(long l1, long l2) {
if (l1 + l2 < 0) {
return summation(String.valueOf(l1), String.valueOf(l2));
} else {
return String.valueOf(l1 + l2);
}
}
// 根据给定的字符串,转换为long并求和,再转换为String
private static String parseString(String s1, String s2, int i) {
long l1 = 0;
long l2 = 0;
if (s1 != null && !s1.equals("")) {
l1 = Long.parseLong(s1);
}
if (s2 != null && !s2.equals("")) {
l2 = Long.parseLong(s2);
}
return (l1 + l2 + i > 0) ? (String.valueOf(l1 + l2 + i)) : "";
}
// 根据给定的字符串,长度len,截取字符串,如果s的长度大于阈值,则按len位一截取,否则不截取,返回字符串本身
private static String[] group(String s, int len) {
String[] ss = null;
if (s.length() > threshold) {
ss = new String[(len / threshold) + 1];
for (int i = 0; i <= len / threshold; i++) {
if (i == len / threshold)
ss[i] = s.substring(i * threshold, len);
else
ss[i] = s.substring(i * threshold, i * threshold
+ threshold);
}
} else {
ss = new String[] { s };
}
return ss;
}
// 根据给定的String数组,下标,判断如果没有越界,则返回下标所在的值,如果越界返回空字符串“”
private static String getString(String[] ss, int index) {
if(index < 0){
return "";
}
if (index > ss.length - 1) {
return "";
} else {
return ss[index];
}
}
}
=============================
太惭愧用如此低效的方法,就当是一种学习的过程,这里jdk提供了一种很高效的方法,java.math.BigInteger类提供了所有基本整数操作的对应运算,还额外提供了好多方法,具体可以参考jdk的官方文档!
经过测试,两个long的最大值相乘耗时竟然0毫秒,太高效了!
BigInteger b1 = new BigInteger("9223372036854775807");
BigInteger b3 = new BigInteger("9223372036854775807");
long st = System.currentTimeMillis();
BigInteger b4 = b1.multiply(b3);//相乘
System.out.println(" BigInteger b4 = "+b4.toString());
long et = System.currentTimeMillis();
System.out.println((et-st));
分享到:
相关推荐
综上所述,当数值超过`long`所能表示的范围时,我们需要使用大整数库或数据类型,配合相应的加减乘算法,同时确保正确处理表达式中的运算顺序。这对于处理大数据、密码学、数学计算等领域至关重要。
这里的大整数是指那些可能超出标准整型变量范围的数值,例如超过`long long`类型的限制。 #### 关键步骤解析 1. **头文件引入**: - `#include <string.h>`:用于处理字符串操作,如`strlen()`函数。 - `#include...
在C#编程语言中,"任意数字相加"是一个基本的操作,它涉及到数值类型的使用、变量的声明以及算术运算符的应用。以下是对这个主题的详细讲解: C#中的数据类型分为两大类:值类型(如int, double, bool等)和引用...
当数值超过标准类型(如int或long)的表示范围时,就需要用到特定的数据结构和算法来存储和操作这些“超级大整数”。这个场景下,我们有一个名为"BigInt.java"的源代码文件,它很可能实现了一个自定义的大整数类,...
在Java编程语言中,处理超大数(即超出标准`int`、`long`类型范围的数字)是一项挑战,因为这些内置数据类型无法容纳非常大的数值。为了应对这种需求,Java提供了`BigInteger`类,它是`java.math`包的一部分,能够...
正确的做法是在加1之前先将`month`转换为数值,这可以通过在`month`前添加`-0`来实现,因为`-0`和任何非零数值相加都会返回该非零数值本身。这样,`month-0 + 1`会确保`month`被转换为数值后再进行加法运算。修改后...
在IT领域,尤其是在编程技术中,处理大整数运算是一项重要的技能,特别是在C语言中,因为C语言标准库并不直接支持超过长整型(long long)的数据类型。本文将深入探讨如何在C语言中实现两个大型整数的相加操作,通过...
在计算机科学中,大数(Big Number)是指超出标准数据类型如整型或浮点型所能表示范围的数值。在处理大数时,通常需要使用特殊的算法和数据结构,因为常规的位运算和算术运算不再适用。本主题将深入探讨如何通过字符...
例如,将一个超出int范围的long long类型值转换为int类型。 3. **未定义行为**:对于某些不合法的类型转换,如将一个指针类型转换为非指针类型,编译器可能不会给出警告或错误,但运行时可能会出现未定义行为。 ##...
在计算机中,通常的整型变量如int或long只能存储一定范围内的数值,而大数相加则涉及到对超过这个范围的数字进行操作。这种情况下,我们可以将大数表示为字符串,或者利用链表的特性来存储每一位数字。 链表作为一...
大数相加通用模板提供了一个简洁而有效的方法,用于处理超出标准数据类型范围的数值相加问题。这种方法利用字符串的灵活性,避免了数值溢出的问题,同时通过简单的逻辑实现了高效的运算。对于参与ACM竞赛的程序员...
由于标准整数类型(如int、long)在面对超过其位宽限制的数值时会溢出,因此需要特殊的数据结构和算法来处理大整数。这个主题在诸如密码学、分布式计算、金融计算以及算法竞赛等领域都有广泛应用。 大整数相加的...
在计算机科学中,由于计算机内存和处理器的限制,...通过C语言和链表的结合,我们可以有效地处理超过标准整型范围的大整数,这对于各种需要大数运算的场景,如加密算法、数值计算和游戏编程等,都有其实际应用价值。
在编程领域,尤其是在进行数值计算时,我们经常会遇到超过普通整型变量范围的数值,这时候就需要使用长整型(Long Integer)数据类型。C++语言提供了`long`和`long long`两种长整型,用来存储大整数。本文将详细讲解...
例如,在C语言中,`int`类型的数值范围通常为-2147483648至2147483647。当需要处理超出这个范围的大数运算时,就需要采用特殊的算法和技术来实现。本篇文章将详细介绍如何使用C语言实现两个大数的相加操作。 #### ...
在C#中,由于内置的数据类型如int、long等存在数值范围限制,当我们需要处理超过这些范围的大整数时,就需要自定义数据结构来存储和操作大数。本文将探讨如何利用链表这一数据结构来实现大数相加。 首先,我们需要...
总之,"long_int200"项目提供了一个自定义的长整数数据类型,旨在处理大数值计算,避免了标准整数类型在处理超过位宽限制的数字时可能出现的问题。通过有效的数据结构和算法设计,它实现了大整数的加法、减法和乘法...
例如,在 C 语言中,`int` 类型的数值范围通常为 -2147483648 到 2147483647,而 `long` 类型的数值范围则更大一些,但仍然有限制。对于更大的数,就需要使用其他方法来表示和处理。 ##### 字符数组的应用 字符...