使用 Java 将双精度值转换为 BigInteger 值的最佳方法
Best way for shifting an double value to BigInteger value with Java
是否有将 double 值转换为 BigInteger 值并稍后返回的正确方法?在最好的情况下不会丢失数据。问题是,我不知道双精度值有多少位小数。但是我需要一个只适用于非十进制值的算法的转换。算法完成后,我必须将其转换回来。
我需要的一个简单示例:例如 2 个双精度值的总和,但 "sum" 函数仅适用于 BigInteger。
您可以通过 5 个步骤完成:
double d1 = 0.1; //your original double
BigDecimal bd1 = new BigDecimal(d1); //convert to BigDecimal
BigInteger bi = bd1.unscaledValue(); //convert to BigInteger
//here do your stuff with the BigInteger
BigDecimal bd2 = new BigDecimal(bi, bd1.scale()); //back to BigDecimal, applying scale
double d2 = bd2.doubleValue(); //convert to double
应用于sum
方法的完整示例
输出:
0.1 + 0.1 = 0.2
0.1 + 10.1 = 10.2
0.1245 + 17.0 = 17.1245
代码:
public static void main(String[] args) {
test(0.1, 0.1);
test(0.1, 10.1);
test(0.1245, 17);
}
private static void test(double d1, double d2) {
System.out.println(d1 + " + " + d2 + " = " + sum(d1, d2));
}
private static double sum(double d1, double d2) {
BigDecimal bd1 = new BigDecimal(d1);
BigDecimal bd2 = new BigDecimal(d2);
int shift = Integer.max(bd1.scale(), bd2.scale());
BigInteger bi1 = bd1.scaleByPowerOfTen(shift).toBigInteger();
BigInteger bi2 = bd2.scaleByPowerOfTen(shift).toBigInteger();
BigInteger sum = sum(bi1, bi2);
return new BigDecimal(sum, shift).doubleValue();
}
private static BigInteger sum(BigInteger i1, BigInteger i2) {
return i1.add(i2);
}
package test;
import java.math.*;
public class HelloWorld{
public static BigInteger sumBigInteger(BigInteger n1,BigInteger n2){
return n1.add(n2);
}
public static double sumDouble(double n1,double n2){
int scale=1;
int max = Math.max(((""+n1).split("\."))[1].length(), ((""+n2).split("\."))[1].length());
for (int i=0;i<max;i++) scale*=10;
BigInteger nbr1 = new BigDecimal(n1*scale).toBigInteger();
BigInteger nbr2 = new BigDecimal(n2*scale).toBigInteger();
return (sumBigInteger(nbr1,nbr2).doubleValue() / scale);
}
public static void main(String []args){
double n1=117.22 , n2=56.945;
System.out.println(n1+" + "+n2+" = "+sumDouble(n1,n2));
}
}
输出:
117.22 + 56.945 = 174.165
这个程序是基于BigDecimal-and-scale的思想,如,但修改为无条件地使用最大可能的所需小数位数。这允许在数字流中使用相同的比例,而无需在处理任何数字之前查看所有数字。代价是它通常 return 不必要的大 BigInteger 值。
比例因子“1e1074”是基于观察到所有有限双精度数都是Double.MIN_VALUE的整数倍,小数点后有1074位小数。 double 小数点后不能有更多的小数位。
import java.math.BigDecimal;
import java.math.BigInteger;
public class Test {
public static void main(String[] args) {
testit(Double.MIN_VALUE);
testit(Double.MAX_VALUE);
testit(0);
testit(1.0);
testit(Math.E);
testit(Math.PI);
}
private static void testit(double d) {
double roundTrip = scaledIntegerToDouble(doubleToScaledInteger(d));
if (d != roundTrip) {
System.out.println("ERROR: " + d + " " + roundTrip);
}
}
public static final BigDecimal scale = new BigDecimal("1e1074");
public static BigInteger doubleToScaledInteger(double d) {
BigDecimal bd = new BigDecimal(d).multiply(scale);
return bd.toBigIntegerExact();
}
public static double scaledIntegerToDouble(BigInteger bi) {
BigDecimal bd = new BigDecimal(bi).divide(scale);
return bd.doubleValue();
}
}
是否有将 double 值转换为 BigInteger 值并稍后返回的正确方法?在最好的情况下不会丢失数据。问题是,我不知道双精度值有多少位小数。但是我需要一个只适用于非十进制值的算法的转换。算法完成后,我必须将其转换回来。
我需要的一个简单示例:例如 2 个双精度值的总和,但 "sum" 函数仅适用于 BigInteger。
您可以通过 5 个步骤完成:
double d1 = 0.1; //your original double
BigDecimal bd1 = new BigDecimal(d1); //convert to BigDecimal
BigInteger bi = bd1.unscaledValue(); //convert to BigInteger
//here do your stuff with the BigInteger
BigDecimal bd2 = new BigDecimal(bi, bd1.scale()); //back to BigDecimal, applying scale
double d2 = bd2.doubleValue(); //convert to double
应用于sum
方法的完整示例
输出:
0.1 + 0.1 = 0.2
0.1 + 10.1 = 10.2
0.1245 + 17.0 = 17.1245
代码:
public static void main(String[] args) {
test(0.1, 0.1);
test(0.1, 10.1);
test(0.1245, 17);
}
private static void test(double d1, double d2) {
System.out.println(d1 + " + " + d2 + " = " + sum(d1, d2));
}
private static double sum(double d1, double d2) {
BigDecimal bd1 = new BigDecimal(d1);
BigDecimal bd2 = new BigDecimal(d2);
int shift = Integer.max(bd1.scale(), bd2.scale());
BigInteger bi1 = bd1.scaleByPowerOfTen(shift).toBigInteger();
BigInteger bi2 = bd2.scaleByPowerOfTen(shift).toBigInteger();
BigInteger sum = sum(bi1, bi2);
return new BigDecimal(sum, shift).doubleValue();
}
private static BigInteger sum(BigInteger i1, BigInteger i2) {
return i1.add(i2);
}
package test;
import java.math.*;
public class HelloWorld{
public static BigInteger sumBigInteger(BigInteger n1,BigInteger n2){
return n1.add(n2);
}
public static double sumDouble(double n1,double n2){
int scale=1;
int max = Math.max(((""+n1).split("\."))[1].length(), ((""+n2).split("\."))[1].length());
for (int i=0;i<max;i++) scale*=10;
BigInteger nbr1 = new BigDecimal(n1*scale).toBigInteger();
BigInteger nbr2 = new BigDecimal(n2*scale).toBigInteger();
return (sumBigInteger(nbr1,nbr2).doubleValue() / scale);
}
public static void main(String []args){
double n1=117.22 , n2=56.945;
System.out.println(n1+" + "+n2+" = "+sumDouble(n1,n2));
}
}
输出:
117.22 + 56.945 = 174.165
这个程序是基于BigDecimal-and-scale的思想,如
比例因子“1e1074”是基于观察到所有有限双精度数都是Double.MIN_VALUE的整数倍,小数点后有1074位小数。 double 小数点后不能有更多的小数位。
import java.math.BigDecimal;
import java.math.BigInteger;
public class Test {
public static void main(String[] args) {
testit(Double.MIN_VALUE);
testit(Double.MAX_VALUE);
testit(0);
testit(1.0);
testit(Math.E);
testit(Math.PI);
}
private static void testit(double d) {
double roundTrip = scaledIntegerToDouble(doubleToScaledInteger(d));
if (d != roundTrip) {
System.out.println("ERROR: " + d + " " + roundTrip);
}
}
public static final BigDecimal scale = new BigDecimal("1e1074");
public static BigInteger doubleToScaledInteger(double d) {
BigDecimal bd = new BigDecimal(d).multiply(scale);
return bd.toBigIntegerExact();
}
public static double scaledIntegerToDouble(BigInteger bi) {
BigDecimal bd = new BigDecimal(bi).divide(scale);
return bd.doubleValue();
}
}