`
tigerl
  • 浏览: 98181 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

超过Long类型表数范围的大数值相加

阅读更多
也许,你很少会遇见这样的计算,当你要计算的值,超过了最大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`所能表示的范围时,我们需要使用大整数库或数据类型,配合相应的加减乘算法,同时确保正确处理表达式中的运算顺序。这对于处理大数据、密码学、数学计算等领域至关重要。

    两个数相加c语言两个数相加c语言

    这里的大整数是指那些可能超出标准整型变量范围的数值,例如超过`long long`类型的限制。 #### 关键步骤解析 1. **头文件引入**: - `#include &lt;string.h&gt;`:用于处理字符串操作,如`strlen()`函数。 - `#include...

    c#任意数字相加

    在C#编程语言中,"任意数字相加"是一个基本的操作,它涉及到数值类型的使用、变量的声明以及算术运算符的应用。以下是对这个主题的详细讲解: C#中的数据类型分为两大类:值类型(如int, double, bool等)和引用...

    超级大整数相加.zip

    当数值超过标准类型(如int或long)的表示范围时,就需要用到特定的数据结构和算法来存储和操作这些“超级大整数”。这个场景下,我们有一个名为"BigInt.java"的源代码文件,它很可能实现了一个自定义的大整数类,...

    Java两超大数相加源码

    在Java编程语言中,处理超大数(即超出标准`int`、`long`类型范围的数字)是一项挑战,因为这些内置数据类型无法容纳非常大的数值。为了应对这种需求,Java提供了`BigInteger`类,它是`java.math`包的一部分,能够...

    vue中 数字相加为字串转化为数值的例子

    正确的做法是在加1之前先将`month`转换为数值,这可以通过在`month`前添加`-0`来实现,因为`-0`和任何非零数值相加都会返回该非零数值本身。这样,`month-0 + 1`会确保`month`被转换为数值后再进行加法运算。修改后...

    c程序 两个大型整数相加

    在IT领域,尤其是在编程技术中,处理大整数运算是一项重要的技能,特别是在C语言中,因为C语言标准库并不直接支持超过长整型(long long)的数据类型。本文将深入探讨如何在C语言中实现两个大型整数的相加操作,通过...

    两个大数相加-字符串实现

    在计算机科学中,大数(Big Number)是指超出标准数据类型如整型或浮点型所能表示范围的数值。在处理大数时,通常需要使用特殊的算法和数据结构,因为常规的位运算和算术运算不再适用。本主题将深入探讨如何通过字符...

    C语言实现数值类型转换源代码

    例如,将一个超出int范围的long long类型值转换为int类型。 3. **未定义行为**:对于某些不合法的类型转换,如将一个指针类型转换为非指针类型,编译器可能不会给出警告或错误,但运行时可能会出现未定义行为。 ##...

    大数相加 中国地质大学数据结构A上机作业1

    在计算机中,通常的整型变量如int或long只能存储一定范围内的数值,而大数相加则涉及到对超过这个范围的数字进行操作。这种情况下,我们可以将大数表示为字符串,或者利用链表的特性来存储每一位数字。 链表作为一...

    大数相加通用模版

    大数相加通用模板提供了一个简洁而有效的方法,用于处理超出标准数据类型范围的数值相加问题。这种方法利用字符串的灵活性,避免了数值溢出的问题,同时通过简单的逻辑实现了高效的运算。对于参与ACM竞赛的程序员...

    大整数相加,计算两个非负整数的和,可以精确计算2的100次方

    由于标准整数类型(如int、long)在面对超过其位宽限制的数值时会溢出,因此需要特殊的数据结构和算法来处理大整数。这个主题在诸如密码学、分布式计算、金融计算以及算法竞赛等领域都有广泛应用。 大整数相加的...

    C语言实现的长整数相加

    在计算机科学中,由于计算机内存和处理器的限制,...通过C语言和链表的结合,我们可以有效地处理超过标准整型范围的大整数,这对于各种需要大数运算的场景,如加密算法、数值计算和游戏编程等,都有其实际应用价值。

    LongAdd 长整型加法

    在编程领域,尤其是在进行数值计算时,我们经常会遇到超过普通整型变量范围的数值,这时候就需要使用长整型(Long Integer)数据类型。C++语言提供了`long`和`long long`两种长整型,用来存储大整数。本文将详细讲解...

    c语言大数相加

    例如,在C语言中,`int`类型的数值范围通常为-2147483648至2147483647。当需要处理超出这个范围的大数运算时,就需要采用特殊的算法和技术来实现。本篇文章将详细介绍如何使用C语言实现两个大数的相加操作。 #### ...

    利用链表实现大数相加

    在C#中,由于内置的数据类型如int、long等存在数值范围限制,当我们需要处理超过这些范围的大整数时,就需要自定义数据结构来存储和操作大数。本文将探讨如何利用链表这一数据结构来实现大数相加。 首先,我们需要...

    long_int200.rar_long_int200_长整数

    总之,"long_int200"项目提供了一个自定义的长整数数据类型,旨在处理大数值计算,避免了标准整数类型在处理超过位宽限制的数字时可能出现的问题。通过有效的数据结构和算法设计,它实现了大整数的加法、减法和乘法...

    大数剧相加

    例如,在 C 语言中,`int` 类型的数值范围通常为 -2147483648 到 2147483647,而 `long` 类型的数值范围则更大一些,但仍然有限制。对于更大的数,就需要使用其他方法来表示和处理。 ##### 字符数组的应用 字符...

Global site tag (gtag.js) - Google Analytics