Din*_*ota 11 .net c# java precision rounding
我正在将.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;
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
调用roundToPrecision(8.7250, 0.05);Java代码给了我8.7这个并不正确.
我甚至尝试BigDecimal在Java中使用引用修改代码如下C#Double Rounding但没有运气.
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;
}
Run Code Online (Sandbox Code Playgroud)
请指导我为解决这个问题需要做些什么.
以下是一些尝试的方案.
10.05; precision = .1; 预期= 10.1;10.12; precision = .01; 预期= 10.12;8.7250; precision = 0.05; 预期= 8.75;10.999; precision = 2; 预期= 10;6.174999999999999; precision = 0.05; 预期= 6.20;注意:我有超过6万个数字,精度可以从1位小数到4位小数不等..NET的输出应该与Java完全匹配.
问题来自于如何在内存中存储和表示双精度数与小数数.有关更多细节,请参阅以下链接:双打 小数
我们来看看它们在代码中的工作方式.使用双精度,参数为8.725和0.05. number / roundPrecision给出174.499...,因为双打不能完全代表174.5.随着小数number / roundPrecision给人174.5,小数都能够准确地表示这一点.所以当174.499...得到四舍五入时,它会向下舍入174而不是175.
使用BigDecimal是朝着正确方向迈出的一步.但是如何在代码中使用它是一个问题.当您创建BigDecimal值时会出现问题.
BigDecimal b = new BigDecimal(number / roundPrecision);
Run Code Online (Sandbox Code Playgroud)
它BigDecimal是从双重创建的,因此不精确已经存在.如果你能够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);
Run Code Online (Sandbox Code Playgroud)
如果函数必须接受并返回双精度数:
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();
}
Run Code Online (Sandbox Code Playgroud)
请记住,双精度数不能精确地表示小数可以表示的相同值.因此返回double的函数不能具有返回小数的原始C#函数的确切输出.
| 归档时间: |
|
| 查看次数: |
1232 次 |
| 最近记录: |