Округление областей с использованием BigDecimals - PullRequest
0 голосов
/ 02 мая 2020

Мы выполняем следующее упражнение: TDD Расчет площади .

Мы написали следующий код:

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;
  }
}

Нам хотелось бы понять, почему существует сложность округления в методе getTotalArea для всех фигур. Например, давайте посмотрим следующую трассировку:

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>

Похоже, что при наличии квадратов и / или кругов метод выдает число, отличное от ожидаемого. Мы думаем, что это из-за того, что метод окружности и квадрата дает уже округленный результат.

Однако тесты требуют округлить круг и квадрат до двух десятичных знаков. Например, если мы изменим метод следующим образом:

  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;
  }

Результаты теста:

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

Кроме того, мы попытались использовать строки для округления результата вверх:

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;
  }
}

И след теста:

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

Похоже, у нас возникают трудности с округлением областей, когда есть квадраты и круги.

Как мы можем правильно его округлить?

Мы уже прочитали:

1 Ответ

0 голосов
/ 02 мая 2020

Для округления до десятичных знаков делайте Math.ceil (область * 100) / 100; это умножит на 100, чтобы вы сохранили 2 десятичных знака, а затем разделите, чтобы вернуть их в правильное положение. Math.ceil () округляется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...