由于双值聚合导致的精度问题

时间:2017-01-17 14:17:56

标签: java double precision

我有一组双值。 现在我已经在每个固定的时间间隔之后聚合了这些值,然后从这些子聚合中计算出宏聚合。

例如:最初有1000个值,我在每5个值后聚合它。然后计算所有值的宏聚合。

现在由于某种原因,我必须用不同的间隔(比如10)再次聚合这些值。

现在,当我比较两个宏聚合以验证我的结果时,我的价值会有所不同。

我们已尝试四舍五入该值然后使用它,但它总是不起作用。

有人可以建议我如何处理这个问题。

我还附上了与此问题相关的示例代码。

注意:我们不想使用BigDecimal而不是double。

public static boolean generateNumbersAndAggregate(int totalIterations)
{
    Random rnd = new Random();
    int accumulateAtN1 = rnd.nextInt(1000)+1;
    int accumulateAtN2 = rnd.nextInt(100)+1;
    int j =1;
    ArrayList<Double> valuesAtN1 = new ArrayList<Double>();
    ArrayList<Double> valuesAtN2 = new ArrayList<Double>();
    double sumAtN1 = 0;
    double sumAtN2 = 0;
    int totalRecords = 500000 /** (rnd.nextInt(1000) + 1)*/;

    System.out.println("totalRecords=" + totalRecords + "  accumulateAtN1=" + accumulateAtN1 + "  accumulateAtN2=" + accumulateAtN2);

    double finalEpsilon = 0;

    while(j < totalRecords)
    {
        double randomDouble = rnd.nextDouble();
        int randomInt = rnd.nextInt(100000);

        /*double d1 = rnd.nextLong();
        double d2 = rnd.nextLong() + 1;*/

        double randomNumber = randomDouble * randomInt;

        finalEpsilon += Math.ulp(randomNumber);

        sumAtN1 += randomNumber;
        sumAtN2 += randomNumber;
        if(j%accumulateAtN1==0)
        {
            valuesAtN1.add(sumAtN1);
            sumAtN1 =0;
        }
        if(j%accumulateAtN2==0)
        {
            valuesAtN2.add(sumAtN2);
            sumAtN2 =0;
        }
        j++;
    }

    if(sumAtN1 > 0)
    {
        valuesAtN1.add(sumAtN1);
    }
    if(sumAtN2 > 0)
    {
        valuesAtN2.add(sumAtN2);
    }

    System.out.println("List Sizes= " + valuesAtN1.size() + "   " + valuesAtN2.size() + "\nRawEpsilon=" + finalEpsilon );

    sumAtN1 =0;
    double list1Epsilon = 0;
    for(double d : valuesAtN1)
    {
        sumAtN1 += d;
        list1Epsilon += Math.ulp(d);
    }
    System.out.println("List1 Eps=" + list1Epsilon );

    sumAtN2 =0;
    double list2Epsilon = 0;
    for(double d : valuesAtN2)
    {
        sumAtN2 += d;
        list2Epsilon += Math.ulp(d);
    }
    System.out.println("List2 Eps=" + list2Epsilon );

    System.out.println("Value1="+sumAtN1+"\nAbsDiff=" + Math.abs(sumAtN1 - sumAtN2) + "\nSumEpsilon=" + Math.ulp(sumAtN2) );

    double mm = list1Epsilon+list2Epsilon+finalEpsilon;

    System.out.println("TotalEpsilon="+mm);

    return isEqual(sumAtN1, sumAtN2, 2, null);
}

public static boolean isEqual(double N1, double N2, double maxDiffAllowed, JobContext context)
{
    if(N1==N2)
    {
        return true;
    }

    long n1 = Math.round(N1);
    long n2 = Math.round(N2);
    if(n1==n2)
    {
        return true;
    }

    double diff = Math.abs(N1-N2);
    double ulp = Math.ulp(N1);
    double finalthresholdval = Math.max(maxDiffAllowed, ulp);
    if(diff <= finalthresholdval)
    {
        return true;
    }

    return false;
}

0 个答案:

没有答案