ASP.net C#十进制到Java双精度之间的舍入不匹配
我正在将.NET代码翻译成Java,遇到了精度不匹配的问题 .NET代码: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
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)上面代码中的code>函数提供了预期的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.05number/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代码>