首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ASP .net C#十进制到Java双倍的四舍五入不匹配

问ASP .net C#十进制到Java双倍的四舍五入不匹配
EN

Stack Overflow用户
提问于 2017-01-13 22:52:14
回答 2查看 1.8K关注 0票数 11

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

.NET代码:

代码语言:javascript
复制
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代码:

代码语言:javascript
复制
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;
}

在Java代码中调用roundToPrecision(8.7250, 0.05);会给我8.7,这是不正确的。

我甚至尝试用BigDecimal修改代码,如下所示,使用这里的引用,C#双舍入,但没有成功。

代码语言:javascript
复制
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.174999999999999;精度= 0.05;期望= 6.20;

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-13 23:40:40

问题在于双小数和小数是如何存储和表示在内存中的。有关更多细节,请参见这些链接:双打 小数

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

使用BigDecimal是朝着正确方向迈出的一步。但是,在您的代码中如何使用它存在一个问题。当您创建BigDecimal值时,问题就出现了。

代码语言:javascript
复制
BigDecimal b = new BigDecimal(number / roundPrecision);

BigDecimal是从双倍创建的,所以不精确已经存在了。如果您能够从一个字符串创建BigDecimal参数,那就更好了。

代码语言:javascript
复制
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);

如果函数必须接受并返回双倍:

代码语言:javascript
复制
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();
}

请记住,双倍不能完全表示小数所能表示的相同值。因此,返回双的函数不能像返回小数的原始C#函数那样具有精确的输出。

票数 7
EN

Stack Overflow用户

发布于 2017-01-24 02:50:13

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

代码语言:javascript
复制
double numberDecimalMultiplier = Math.round((float)(number / roundPrecision));
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41644691

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档