使用Java将双精度值转换为BigInteger值的最佳方法

使用Java将双精度值转换为BigInteger值的最佳方法,java,double,biginteger,Java,Double,Biginteger,有没有合适的方法将双精度值转换为双精度整数值,然后再转换回来?在不丢失数据的最佳情况下。问题是,我不知道双精度值有多少个小数位。但是我需要这个转换来实现一个只适用于非十进制值的算法。算法完成后,我必须将其转换回来 我需要的一个简单示例:例如,两个双精度值的总和,但“sum”函数仅适用于biginger。您可以通过5个步骤完成: double d1 = 0.1; //your original double BigDecimal bd1 = new BigDecimal(d1); //conver

有没有合适的方法将双精度值转换为双精度整数值,然后再转换回来?在不丢失数据的最佳情况下。问题是,我不知道双精度值有多少个小数位。但是我需要这个转换来实现一个只适用于非十进制值的算法。算法完成后,我必须将其转换回来


我需要的一个简单示例:例如,两个双精度值的总和,但“sum”函数仅适用于biginger。

您可以通过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

代码:


该程序基于中的BigDecimal和scale思想,但修改为无条件使用所需的最大比例。这允许在数字流中使用相同的比例,而不必在处理任何数字之前查看所有数字。代价是它通常会返回不必要的大整数值

比例因子“1e1074”基于以下观察结果:所有有限双精度数字都是double.MIN_值的整数倍,小数点后有1074位小数。小数点后不能有更多的小数位数

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();
  }
}

这是否意味着,我需要知道小数位数最多的双精度值(在我的“sum”函数中),还是它适用于任何十进制值?BigDecimal和BigInteger是不可变的。除非我们丢失了bd和bi的引用,否则我们只需从bd.doubleValue()返回d1即可。@DanielMüssig抱歉我误解了你的问题-是的,如果涉及两个double,你需要知道哪个BigDecimal的刻度最大,并将其用于所有的double值。好的,有没有办法,在哪里我不必知道每一个值?@assylias我根据这个值添加了一个答案,但使用了最大规模的想法。它解释了1074是从哪里来的,我想OP只需要取double的整数部分,并将其存储在BigInteger中。不是吗@assylias??不是,就像我在问题末尾写的那样:例如:我想要两个双精度值的和,但“sum”函数只适用于BigInteger。@DanielMüssig我现在得到了它,我将根据您的需要编辑我的答案。@assylias现在不截断小数:-)
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
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();
  }
}