也许,你很少会遇见这样的计算,当你要计算的值,超过了最大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));
分享到:
相关推荐
今天小编就为大家分享一篇vue中 数字相加为字串转化为数值的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
当N!过大,无法用INT LONG __INT64 接收时,只能通过二维数组,将每一位数据截取出来。
加法运算符 (+) 两数相加。 And 运算符 执行两个表达式的逻辑连接。 Array 函数 返回含一数组的 变体 。 Asc 函数 返回字符串首字母的 ANSI 字符代码。 赋值运算符 (=) 给变量或属性赋值。 Atn 函数 返回数的...
加法运算符 (+) 两数相加。 And 运算符 执行两个表达式的逻辑连接。 Array 函数 返回含一数组的 变体 。 Asc 函数 返回字符串首字母的 ANSI 字符代码。 赋值运算符 (=) 给变量或属性赋值。 Atn 函数 返回数的...
下表列出了Turbo C中各类整型量所分配的内存字节数及数的表示范围。 类型说明符 数的范围 分配字节数 int -32768~32767 ■■ short int -32768~32767 ■■ signed int -32768~32767 ■■ unsigned int 0~65535 ■...
byte,short,char 只要在表数范围中,不用强转可以直接进行赋值。但是要是超出范围,就必须要进行强转了 类型的优先级别:byte,short,char,int,long,float,double (低–高) 右>左–强制类型转换 右<左–自动转换 ...
CLng 函数 返回已被转换为 Long 子类型的变体的表达式。 颜色常数 颜色常数列表。 比较常数 用于比较运算的常数列表。 连接运算符 (&) 强制两个表达式的字符串连接。 Const 语句 声明用于字母值的常数。 Cos ...
加法运算符 (+) 两数相加。 And 运算符 执行两个表达式的逻辑连接。 Array 函数 返回含一数组的 变体 。 Asc 函数 返回字符串首字母的 ANSI 字符代码。 赋值运算符 (=) 给变量或属性赋值。 Atn 函数 返回数的...
加法运算符 (+) 两数相加。 And 运算符 执行两个表达式的逻辑连接。 Array 函数 返回含一数组的 变体 。 Asc 函数 返回字符串首字母的 ANSI 字符代码。 赋值运算符 (=) 给变量或属性赋值。 Atn 函数 返回数的...
操作这些原始数据类型数据的字节码(指令)本身就已经指出了操作数的数据类型,例如iadd、ladd、fadd和dadd指令都是把两个数相加,其操作数类型分别是int、long、float和double。虚拟机没有给boolean(布尔)类型设置...
注意:两个 byte 数相加,变 int 型) short 16bit, -2^15~2^15-1 (2^15=32768) int 32bit, -2^31~2^31-1 (2147483648,20亿,10位有效数字) long 64bit, -2^63~2^63-1 (900亿亿,20位有效数字) float 32bit, 9...
对于高精度运算一般基本浮点型double、long double都满足不了精度要求,时需要用数组来存储数值,并用数组每一个元算参与运算,执行相乘和移位相加,达到高精度要求。
Numeric constant too large -------------------数值常太大 Out of memory -------------------内存不够用 houjiuming Parameter ''xxx'' is never used ------------------能数xxx没有用到 Pointer required on...
C) 双精度类型double比单精度类型float具有更高的精度和更大的表示范围,但float类型具有速度快、占用内存小的优点。 D) 在Java中布尔值可以用true或false来表示,但是同时也可以用1或0来表示。 题目5:b 程序...
内容及步骤: 1、 设计一个图的类,采用临接表法进行存储,该图每个结点的数据类型类模板的模板参数进行定义(注:需先设计一个结点类Node); 2、 为该类分别设计一个实现深度优先搜索和广度优先搜索的成员...