简体   繁体   English

使用 BigDecimals 舍入区域

[英]Rounding areas using BigDecimals

We are doing the following exercise: TDD Area Calculations .我们正在做以下练习: TDD 面积计算

We have written the following code:我们编写了以下代码:

import java.math.*;
public class Calculator{
  public double getTotalArea(Triangle triangle){
    double area = triangle.base*triangle.height/2;
    System.out.println("getTotalArea of triangle: "+area);
    return area;
  }    

  public double getTotalArea(Square square){
    double area = BigDecimal.valueOf(square.side*square.side).setScale(2,BigDecimal.ROUND_HALF_EVEN).doubleValue();
    System.out.println("getTotalArea of square: "+area);
    return area;
  }      

  public double getTotalArea(Rectangle rectangle){
    double area = rectangle.width*rectangle.height;
    System.out.println("getTotalArea of rectangle: "+area);
    return area;
  }

  public double getTotalArea(Circle circle){
    double area = BigDecimal.valueOf(circle.radius*circle.radius*Math.PI).setScale(2,BigDecimal.ROUND_HALF_EVEN).doubleValue();
    System.out.println("getTotalArea of circle: "+area);
    return area;
  }

  public double getTotalArea(Shape ...shapes){
    Calculator calc = new Calculator();
    BigDecimal result= BigDecimal.ZERO;

    for(Shape shape : shapes){
      if(shape instanceof Triangle){
        result = result.add(BigDecimal.valueOf(calc.getTotalArea(new Triangle(shape.base,shape.height))));
        System.out.println("getTotalArea adding 📐: "+result);
      }
      if(shape instanceof Square){
        result=result.add(BigDecimal.valueOf(calc.getTotalArea(new Square(shape.side))));
        System.out.println("getTotalArea adding 🔲: "+result);
      }
      if(shape instanceof Rectangle){
        result=result.add(BigDecimal.valueOf(calc.getTotalArea(new Rectangle(shape.height,shape.width))));
        System.out.println("getTotalArea adding 🧱: "+result);
      }
      if(shape instanceof Circle){
        result=result.add(BigDecimal.valueOf(calc.getTotalArea(new Circle(shape.radius))));
        System.out.println("getTotalArea adding 🔵: "+result);
      }
    }
    System.out.println("getTotalArea of all shapes result: "+result+"\n\n");
    return result.setScale(2,BigDecimal.ROUND_HALF_EVEN).doubleValue();
  }

}

class Shape{
  double base, height, side, width, radius;    
}

class Triangle extends Shape{
  Triangle(double base, double height){
    this.base=base;
    this.height=height;
  }
}

class Square extends Shape{
  Square(double side){
    this.side=side;
  }  
}

class Rectangle extends Shape{
  Rectangle(double height, double width){
    this.height=height;
    this.width=width;
  }
}

class Circle extends Shape{
  Circle(double radius){
    this.radius=radius;
  }
}

We would like to understand why there is a rounding difficulty in the method getTotalArea of all shapes.我们想了解为什么在所有形状的 getTotalArea 方法中存在舍入困难。 For example, let`s see the following trace:例如,让我们看看以下跟踪:

getTotalArea of square: 1425.6
getTotalArea of square: 1425.6
getTotalArea adding 🔲: 1425.6
getTotalArea of circle: 31.92
getTotalArea adding 🔵: 1457.52
getTotalArea of all shapes result: 1457.52

expected:<1457.53> but was:<1457.52>

It looks like when there are squares and/or circles, the method outputs a different number than the expected.看起来当有正方形和/或圆形时,该方法输出的数字与预期的数字不同。 We think it is because of the circle and square method give an already rounded result.我们认为这是因为圆形和方形方法给出了一个已经四舍五入的结果。

However, tests require to round circle and square result to two decimals.但是,测试需要将圆形和方形结果四舍五入到小数点后两位。 For example if we change the method as follows:例如,如果我们将方法更改如下:

  public double getTotalArea(Circle circle){
    double area = circle.radius*circle.radius*Math.PI;
    //double area = BigDecimal.valueOf(circle.radius*circle.radius*Math.PI).setScale(2,BigDecimal.ROUND_HALF_EVEN).doubleValue();
    System.out.println("getTotalArea of circle: "+area);
    return area;
  }

The tests outputs:测试输出:

getTotalArea of circle: 28.274333882308138
expected:<28.27> but was:<28.274333882308138>

In addition we tried to use strings to round the result up:此外,我们尝试使用字符串对结果进行四舍五入:

import java.math.*;
public class Calculator{
  public double getTotalArea(Triangle triangle){
    double area = triangle.base*triangle.height/2;
    System.out.println("getTotalArea of triangle: "+area);
    return area;
  }    

  public double getTotalArea(Square square){
    double area = BigDecimal.valueOf(square.side*square.side).setScale(2,BigDecimal.ROUND_HALF_EVEN).doubleValue();
    System.out.println("getTotalArea of square: "+area);
    return area;
  }      

  public double getTotalArea(Rectangle rectangle){
    double area = rectangle.width*rectangle.height;
    System.out.println("getTotalArea of rectangle: "+area);
    return area;
  }

  public double getTotalArea(Circle circle){
    double area = BigDecimal.valueOf(circle.radius*circle.radius*Math.PI).setScale(2,BigDecimal.ROUND_HALF_EVEN).doubleValue();
    System.out.println("getTotalArea of circle: "+area);
    return area;
  }

  public double getTotalArea(Shape ...shapes){
    Calculator calc = new Calculator();
    BigDecimal result= BigDecimal.ZERO;

    for(Shape shape : shapes){
      if(shape instanceof Triangle){
        result = result.add(BigDecimal.valueOf(calc.getTotalArea(new Triangle(shape.base,shape.height))));
        System.out.println("getTotalArea adding 📐: "+result);
      }
      if(shape instanceof Square){
        result=result.add(BigDecimal.valueOf(calc.getTotalArea(new Square(shape.side))));
        System.out.println("getTotalArea adding 🔲: "+result);
      }
      if(shape instanceof Rectangle){
        result=result.add(BigDecimal.valueOf(calc.getTotalArea(new Rectangle(shape.height,shape.width))));
        System.out.println("getTotalArea adding 🧱: "+result);
      }
      if(shape instanceof Circle){
        result=result.add(BigDecimal.valueOf(calc.getTotalArea(new Circle(shape.radius))));
        System.out.println("getTotalArea adding 🔵: "+result);
      }
    }
    System.out.println("getTotalArea of all shapes result: "+result+"\n\n");

    String s = String.valueOf(result.doubleValue());
    System.out.println("s: "+s);
    System.out.println("s.indexOf(\".\"): "+s.indexOf("."));
    String threeDecimals = s.substring(0,s.length() - s.indexOf(".") >= 4 ? s.indexOf(".")+4 : s.length());
    double number = Double.parseDouble(threeDecimals);
    String decimalPart = threeDecimals.substring(threeDecimals.indexOf(".")+1);

    if(decimalPart.length() > 2 && Character.getNumericValue(threeDecimals.charAt(threeDecimals.length()-1)) > 5){
      number = number+0.01;
    }
    s = String.valueOf(number);
    String twoDecimals = s.substring(0,s.length() - s.indexOf(".") >= 3 ? s.indexOf(".")+3 : s.length());



    return Double.parseDouble(twoDecimals);

  }

}

class Shape{
  double base, height, side, width, radius;    
}

class Triangle extends Shape{
  Triangle(double base, double height){
    this.base=base;
    this.height=height;
  }
}

class Square extends Shape{
  Square(double side){
    this.side=side;
  }  
}

class Rectangle extends Shape{
  Rectangle(double height, double width){
    this.height=height;
    this.width=width;
  }
}

class Circle extends Shape{
  Circle(double radius){
    this.radius=radius;
  }
}

And the tests' trace is:测试的痕迹是:

getTotalArea of square: 7439.73
getTotalArea of square: 7439.73
getTotalArea adding 🔲: 7439.73
getTotalArea of circle: 12722.91
getTotalArea adding 🔵: 20162.64
getTotalArea of all shapes result: 20162.64


s: 20162.64
s.indexOf("."): 5
res: 20162.64

So it looks like we have a difficulty rounding areas when there are squares and circles.因此,当有正方形和圆形时,看起来我们很难对区域进行四舍五入。

How could we round it correctly?我们怎样才能正确地舍入它?

We have already read:我们已经阅读:

To Round up to decimal places do Math.ceil(area * 100) / 100;要四舍五入到小数位,请执行 Math.ceil(area * 100) / 100; this will multiple by 100 to make sure you keep the 2 decimals, then divide to return them to their proper position.这将乘以 100 以确保保留 2 位小数,然后除以将它们返回到正确的 position。 Math.ceil() rounds up. Math.ceil() 四舍五入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM