Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ASP.net C#十进制到Java双精度之间的舍入不匹配_Java_C#_.net_Rounding_Precision - Fatal编程技术网

ASP.net C#十进制到Java双精度之间的舍入不匹配

ASP.net C#十进制到Java双精度之间的舍入不匹配,java,c#,.net,rounding,precision,Java,C#,.net,Rounding,Precision,我正在将.NET代码翻译成Java,遇到了精度不匹配的问题 .NET代码: private decimal roundToPrecision(decimal number, decimal roundPrecision) { if (roundPrecision == 0) return number; decimal numberDecimalMultiplier = Math.Round(number / roundPrecision, MidpointRou

我正在将.NET代码翻译成Java,遇到了精度不匹配的问题

.NET代码:

private decimal roundToPrecision(decimal number, decimal roundPrecision)
{
    if (roundPrecision == 0)
        return number;
    decimal numberDecimalMultiplier = Math.Round(number / roundPrecision, MidpointRounding.AwayFromZero);
    return numberDecimalMultiplier * roundPrecision;
}
呼叫
roundToPrecision(8.7250,0.05)函数提供了预期的
8.75

函数到Java的转换/转换如下所示。我找不到确切的答案
Math.Round
选项

Java代码:

public double roundToPrecision(double number, double roundPrecision) {
    if (roundPrecision == 0)
        return number;
    int len = Double.toString(roundPrecision).split("\\.")[1].length();
    double divisor = 0d;
    switch (len) {
        case 1:
            divisor = 10d;
            break;
        case 2:
            divisor = 100d;
            break;
        case 3:
            divisor = 1000d;
            break;
        case 4:
            divisor = 10000d;
            break;
    }
    double numberDecimalMultiplier = Math.round(number / roundPrecision);
    double res = numberDecimalMultiplier * roundPrecision;
    return Math.round(res * divisor) / divisor;
}
呼叫
roundToPrecision(8.7250,0.05)给了我
8.7
,这是不正确的

我甚至尝试用
BigDecimal
在Java中使用这里的引用修改代码,如下所示,但没有成功

public double roundToPrecision(double number, double roundPrecision) {
    if (roundPrecision == 0)
        return number;
    int len = Double.toString(roundPrecision).split("\\.")[1].length();
    double divisor = 0d;
    switch (len) {
        case 1:
            divisor = 10d;
            break;
        case 2:
            divisor = 100d;
            break;
        case 3:
            divisor = 1000d;
            break;
        case 4:
            divisor = 10000d;
            break;
    }
    BigDecimal b = new BigDecimal(number / roundPrecision);
    b = b.setScale(len,BigDecimal.ROUND_UP);
    double numberDecimalMultiplier = Math.round(b.doubleValue());
    double res = numberDecimalMultiplier * roundPrecision;
    return Math.round(res * divisor) / divisor;
}
请指导我需要做什么来解决这个问题

这里有两个场景可以尝试

  • 数字=
    10.05
    ;精度=
    .1
    ;预期=
    10.1
  • 数字=
    10.12
    ;精度=
    .01
    ;预期=
    10.12
  • 数字=
    8.7250
    ;精度=
    0.05
    ;预期=
    8.75
  • 数字=
    10.999
    ;精度=
    2
    ;预期=
    10
  • 数字=
    6.1749999999999
    ;精度=
    0.05
    ;预期=
    6.20

注:我有超过6万个数字,精度从1位小数到4位小数不等。NET的输出应该与Java完全匹配。

问题来自于双精度和小数在内存中的存储和表示方式。有关更多详细信息,请参见以下链接:

让我们看看它们在代码中是如何工作的。使用双精度,参数为8.725和0.05
number/roundPrecision
给出了
174.499…
,因为double不能准确表示174.5。对于小数
number/roundPrecision
给出的
174.5
,小数能够准确地表示这一点。因此,当
174.499…
四舍五入时,它将四舍五入到
174
,而不是
175

使用
BigDecimal
是正确的一步。但是,在代码中如何使用它存在一个问题。在创建BigDecimal值时会出现问题

BigDecimal b = new BigDecimal(number / roundPrecision);
BigDecimal
是从一个double创建的,因此不精确性已经存在。如果您能够从字符串中创建
BigDecimal
参数,那就更好了

public static BigDecimal roundToPrecision(BigDecimal number, BigDecimal roundPrecision) {
    if (roundPrecision.signum() == 0)
        return number;
    BigDecimal numberDecimalMultiplier = number.divide(roundPrecision, RoundingMode.HALF_DOWN).setScale(0, RoundingMode.HALF_UP);
    return numberDecimalMultiplier.multiply(roundPrecision);
}


BigDecimal n = new BigDecimal("-8.7250");
BigDecimal p = new BigDecimal("0.05");
BigDecimal r = roundToPrecision(n, p);
如果函数必须接收并返回双精度:

public static double roundToPrecision(double number, double roundPrecision)
{
    BigDecimal numberBig = new BigDecimal(number).
            setScale(10, BigDecimal.ROUND_HALF_UP);
    BigDecimal roundPrecisionBig = BigDecimal.valueOf(roundPrecision);
    if (roundPrecisionBig.signum() == 0)
        return number;
    BigDecimal numberDecimalMultiplier = numberBig.divide(roundPrecisionBig, RoundingMode.HALF_DOWN).setScale(0, RoundingMode.HALF_UP);
    return numberDecimalMultiplier.multiply(roundPrecisionBig).doubleValue();
}

请记住,double不能准确地表示小数可以表示的相同值。因此,返回double的函数不能像返回小数的原始C#函数那样有精确的输出。

这里真正的问题是Math.round有两个定义。一个返回long,而另一个返回int!当你提供一个双倍的,它运行了一个很长的时间。要解决这个问题,只需将您的输入转换为一个float,使其运行返回int的float

double numberDecimalMultiplier = Math.round((float)(number / roundPrecision));

谢谢你的回答。不过,我已经试过了。试试senarios 1和2(我已经更新了问题)。它们不会在您的实现中给出预期的结果;
BigDecimalNumberDecimalMultiplier=number.divide(roundPrecision).setScale(0,RoundingMode.天花板)上没有可精确表示的十进制结果
当数字为10.0且精度为0.1时,当它引发异常时,您的参数是什么?当数字为10.0且精度为0.1时,此案例失败
number=10.025d;精度=.05d;预期=10.05d