0

We are doing the following exercise: TDD Area Calculations.

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. 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:

Yone
  • 2,064
  • 5
  • 25
  • 56

1 Answers1

0

To Round up to decimal places do 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. Math.ceil() rounds up.

RIVERMAN2010
  • 427
  • 3
  • 9