Java loss of precision with Heron's formula - java

I'm trying to print the area and perimeter of a triangle with the given lengths. I have successfully printed the correct perimeter however, my area is incorrect (the output of the area is 0.00). I realized that it is a loss of precision error but, I am unable to solve it. Will anyone please examine this code and point out the issue, specifically at the instance method,calculateArea? Thank you.
public class Triangle
{
private int sideA=0, sideB=0, sideC=0, perimeter=0;
private double area=0;
public Triangle()
{
}
public Triangle(int a, int b, int c)
{
setSides(a,b,c);
}
public void setSides(int a,int b, int c)
{
sideA=a;
sideB=b;
sideC=c;
}
public void calculateArea()
{
int s;
s=(int)perimeter/2;
double area=Math.sqrt(s*(s-sideA)*(s-sideB)*(s-sideC));
}
public void calculatePerimeter()
{
perimeter=sideA+sideB+sideC;
}
public void printTriangle()
{
System.out.printf("The triangle with sides %d , %d and %d has an area of %.3f and perimeter %d%n", sideA, sideB, sideC, area, perimeter);
}
}
For reference(you don't need to correct it or anything), here's my other code.
public class TriangleRunner
{
public static void main(System[]args)
{
Triangle isoceles = new Triangle();
isoceles.setSides(3,3,3);
isoceles.calculateArea();
isoceles.calculatePerimeter();
isoceles.printTriangle();
Triangle right345 = new Triangle();
right345.setSides(3,4,5);
right345.calculateArea();
right345.calculatePerimeter();
right345.printTriangle();
}
}

You are using perimeter in calculateArea, but that is only calculated in calculatePerimeter, which isn't called yet, so perimiter is still 0. You can simply call calculatePerimeter first, before calling calculateArea, but it may be best to call calculatePerimeter in calculateArea to make sure it's available to you.
Because the perimeter value depends on the other values, it isn't a good idea to have it as an instance variable. You may want to return that value in calculatePerimeter, using it as a local variable when necessary.
Also, change s in calculateArea to a double, and divide by the double literal 2.0 instead of 2, to force floating-point calculations.
With these changes I get correct output.

Related

Solving Ordinary Differential Equations using Euler in Java Programming

I'm trying to write a java program that will solve any ordinary differential equations using Euler method, but I don't know how to write a code to get any differential equation from the user. I was only able to write the code to solve a predefined ordinary differential equations.
I was able to come with a code to solve some particular ordinary differential equations which were written as functions in the program, I also made research online to look for similar problems but it seem they also wrote it to solve some designated problem not general questions on ordinary differential equations. This was found in most of the article have read online.
Here is my Euler class;
import java.lang.Math;
public class Euler {
private double x0, y0, x1, y1, h, actual;
public Euler (double initialx, double initialy,double stepsize,double finalx1) {
x0 = initialx; y0 = initialy; h=stepsize; x1 = finalx1;
}
public void setEuler (double initialx, double initialy,double stepsize,
double finalx1){
x0 = initialx;y0 = initialy;h =stepsize;x1 = finalx1;
}
public double getinitialx(){
return x0;
}
public double getinitialy(){
return y0;
}
public double getinitialexact(){
return (double) (0.9048*Math.exp(0.1*x0*x0));
}
double func(double x, double y){
return (double) (0.2*x*y);
}
double funct(double x){
return (double) (java.lang.Math.exp(0.1*x*x));
}
public double getinitialerror(){
return (double) Math.abs(actual - y0);
}
public double getEulerResult(){
for (double i = x0 + h; i < x1; i += h){
y0 = y0 + h *(func(x0,y0));
x0 += h;
double actual = (0.9048*funct(x0));
double error = Math.abs(actual - y0);
System.out.printf("%f\t%f\t%f\t%f\n",x0,y0,actual, error);
}
return y0;
}
}
Here is my Driver's class
import java.util.Scanner;
public class EulerTest {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Euler myEuler = new Euler(1.0,1.0,0.1,1.5);
System.out.println( "x\t explicit\tactual\t error\t " );
System.out.printf("%f\t%f\t%f\t%f\n", myEuler.getinitialx(),
myEuler.getinitialy(),myEuler.getinitialexact(),
myEuler.getinitialerror());
System.out.printf("my approximated value is %f\n\n",
myEuler.getEulerResult ());
System.out.println("enter another initial value of x: ");
double initialx = input.nextDouble();
System.out.println("enter another initial value of y: ");
double initialy = input.nextDouble();
System.out.println("enter another stepsize value of h: ");
double stepsize = input.nextDouble();
System.out.println("enter another upper bound of x: ");
double finalx1 = input.nextDouble();
myEuler.setEuler(initialx,initialy,stepsize,finalx1);
System.out.println( "x\t explicit\tactual\t error\t " );
System.out.printf("%f\t%f\t%f\t%f\n", myEuler.getinitialx(),
myEuler.getinitialy(),myEuler.getinitialexact(),
myEuler.getinitialerror());
System.out.printf("my approximated value is %f\n\n",
myEuler.getEulerResult ());
}
}
I will be glad if i can en lighted on how to write the java code to collect any ordinary differential equation from the user so as to solve using Euler's method.
What you are looking for is the ability to compile some code at run time, where part of the code is supplied by the user.
There is a package called JOOR that gives you a Reflect class that contains a compile method. The method takes two parameters (a package name:String and the Java code:String).
I've never personally used it, so can not vouch for its robustness, but here is a tutorial and the javadoc:
https://www.jooq.org/products/jOOR/javadoc/latest/org.jooq.joor/org/joor/Reflect.html#compile(java.lang.String,java.lang.String)
https://blog.jooq.org/2018/04/03/how-to-compile-a-class-at-runtime-with-java-8-and-9/
In your case, you would put your user supplied function in place of the following line of code:
return \"Hello World!\";\n"
Beware, you need to be 100% absolutely unconditionally guaranteed that the user can only ever enter a function to be solved. If they are supplying code, remember that unless you take safeguards, the code they enter could very easily be code the removes all of the files on your hard drive (or worse).
For the second part of your question - how do i implement a solution in Java using Euler's method, perhaps check out this link: Euler's Method in java or this https://rosettacode.org/wiki/Euler_method#Java which has it in pretty much every language you can imagine (and probably some you can't).

For loop and if statement within a method

I am new to using java and am having some issues in my java class right now and will be needing help with my specific code. I try to look at others questions on here all the time but it's never exactly what I need. Here are my directions:
Create a Java file called CompoundInterestYourLastName. Write a method called computeBalance() that computes the balance of a bank account with a given initial balance and interest rate, after a given number of years. Assume interest is compounded yearly.
Use a loop to control the iterations through the years in your method.
Your method should return a double value.
In your main method, run the following tests to verify your method is working correctly.
System.out.printf("Your total is $%.2f", computeBalance(1000, .045, 3));
// should return $1141.17
I am using eclipse and my only current error is in the comments. I also want some general tips and let me know if my logic is wrong. It probably is. :D
Here is what I have currently although I have been trying different things:
import java.util.Scanner;
import java.lang.Math;
public class CompoundInterestTidwell {
public static void main(String[] args) {
double compInt = computeBalance(1000, 0.045, 3);
System.out.printf("Your new balance is $%.2f", compInt);
}
// Getting arror for line of code below.
// Error: This method must return a result of type double
public static double computeBalance(int P, double r, int t) {
// Formula for compounding interest
// A = P(1+(r/n))^(n(t))
// The examples to check my math had rate already divided by 100 so I left out r/n.
for(int c = 0; c <= t; c++ ) {
// deleted 'n' from equation because it need to equal 1 anyways.
double compInt = Math.pow(P*(1+r), t);
if (c < t) {
c++;
return compInt;
}
}
}
}
Thanks.
Your function computeBalance doesn't guarantee to return a value, because the only return statement is in an if clause, within a loop (making it two conditions deep).
This is a thing the compiler is warning you about. Basically it scans your code and makes sure that a function declared as double will actually return a valid value of type double and so on.
If you add a return statement at the end of the body in the function (or throw an error) it should compile.
I am not exactly sure what your function does in technical terms, but I've rewritten it so it should return the same value, but should now actually compile.
public static double computeBalance(int P, double r, int t) {
// Formula for compounding interest
// A = P(1+(r/n))^(n(t))
// The examples to check my math had rate already divided by 100 so I left out r/n.
double compInt = 0; // Declare compInt outside the loop.
for(int c = 0; c <= t; c++ ) {
// deleted 'n' from equation because it need to equal 1 anyways.
compInt = Math.pow(P*(1+r), t);
if (c < t) {
c++;
break; // Break instead of return, will immediately
// go to the return statement outside the loop.
}
}
return compInt; // Moved the return statement to outside the loop so
// the function always will return a double.
}

Passing values of different data types in Method Overloading

I pass a double value to the method that is being overloaded but it takes it as float and invokes the method for finding area of square. Float values should have an "f" to their end to be considered float right? so why does my program invoke float 'area of square' when it's supposed to invoke 'area of circle'?
public class App {
public void calArea(float a) {
System.out.println("Area of square is Side x Side : " + a * a);
}
public void calArea(float a, float b) {
System.out.println("Area of rectangle is length x width" + a * b);
}
public void calArea(double r) {
double area = (Math.PI * r * r);
System.out.println("Area of circle is Radius x Radius x PI : " + area);
}
public static void main(String[] args) {
App app = new App();
app.calArea(5);
}
}
I just post my comment as an answer, because it is the only way to resolve your problem without casting.
Instead of using double and float to distinguish what areas should be calculated. Just name them differently. This will remove a lot of headache when seeing your code.
Will app.calArea(5) calculate the area of a circle or a square?
So just change your code to this:
public class App {
public void calAreaSquare(double a) {
System.out.println("Area of square is Side x Side : " + a * a);
}
public void calAreaRectangle(double a, double b) {
System.out.println("Area of rectangle is length x width" + a * b);
}
public void calAreaCircle(double r) {
double area = (Math.PI * r * r);
System.out.println("Area of circle is Radius x Radius x PI : " + area);
}
public static void main(String[] args) {
App app = new App();
app.calAreaCircle(5);
}
}
I would also suggest just using double only, for the enhanced precision.
Simplest way to invoke method of 'area of circle' is just by calling from main method as "app.calArea(5d);". By writing 5d or 5.0d area of circle method will be called because the value 5d is considered as double. And if you want to invoke method of 'area of square', you can do it in either way by (1) app.calArea(5f); or (2) app.calArea(5).
So, if you want to continue with your method overloading and invoke 'area of circle' you can do it in this way
public class App {
public void calArea(float a) {
System.out.println("Area of square is Side x Side : " + a * a);
}
public void calArea(float a, float b) {
System.out.println("Area of rectangle is length x width" + a * b);
}
public void calArea(double r) {
double area = (Math.PI * r * r);
System.out.println("Area of circle is Radius x Radius x PI : " + area);
}
public static void main(String[] args) {
App app = new App();
app.calArea(5d);
}
}
Here are some quotes from the language spec that explains this behaviour.
Section 15.12.2.5 Choosing the Most Specific Method
If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen. The
informal intuition is that one method is more specific than another if
any invocation handled by the first method could be passed on to the
other one without a compile-time error.
In your case, both calArea(float) and calArea(double) are applicable for a single int argument (int can be converted to either float or double through a primitive widening conversion).
Now the compiler needs to decide which is more specific. In the end, the compiler chose calArea(float) because it is more specific than calArea(double).
Every call that is applicable to calArea(float) is applicable to calArea(double) (implicit primitive widening conversion from float to double), but not vice versa (you need a cast to convert from double to float).
Therefore the compiler chose the calArea(float) overload.
to answer "why does my program invoke float 'area of square' when it's supposed to invoke 'area of circle'?"
This is because the exact matched method which accept int argument is not found hence based on widening, nearest method that matched is called(here its float)
widening happens in below order
byte - > short - > int - > long - > float - > double
in your case its (int - > long - > float - > double)
as you are passing int argument hence nearest match is a method that accepts float argument hence calArea(float a) is called
[to check this try including a method that accepts long argument and you will see it will get a chance to execute instead of earlier method that accepts float argument]
e.g
public void calArea(int a) {
System.out.println("int");
}
public void calArea(long a) {
System.out.println("long");
}
public void calArea(float a) {
System.out.println("float");
}
public void calArea(double a) {
System.out.println("double");
}
method call is - calArea(5);
case 1: lets say no method commented
here method accepting int argument will be called.
case 2: now comment /remove first method (accepting int argument)
here method accepting long argument will be called.
case 3: now again comment method 1 and 2 method
here method accepting float argument will be called.
and so on...
As you are passing int value not double.... so 'area of square' is being calculated. For 'area of circle' you have to pass decimal value as argument while calling the function.

Trying to make a simple falling ball program

This is what I have so far. It tells me that I have a syntax error on the lines marked below, saying that it expected a "{" and a "}" respectively, without the double quotes around them. Any suggestions?
public class attempt1 {
//use Euler-Richardson algorithm
//defining the initial conditions
double v0=30;
double theta=40;
double x0=0;
double y0=0;
double v0x=v0*Math.cos(Math.toRadians(theta));
double v0y=v0*Math.sin(Math.toRadians(theta));
double dt= .01;
double ax=0;
double ay=-9.8;
double x=0;
double y=0; //this line here, on the semi-colon
while (y>=0) {
double vx= v0x+1/2*ax*dt;
double vy= v0y+1/2*ay*dt;
double x= x0+1/2*vx*dt;
double y= y0+1/2*vy*dt;
if (y<=0){System.out.println(x);}
}
} //and right over here, on the brace itself
You are trying to run statements inside a class body. They should be in a method. like this:
public class Attempt1{
private void doSomething(){
//example code
int a = 1 + 1;
while (a < 2) {
//do random stuff
}
}
}
Right now you have something similar to this:
public class Attempt1 {
//while{...} <---- WRONG!
}
Statements should be in a method (sometimes called function) at all times.
You can however put variables outside a method. This will make them accessible for all methods in that class.
You should check out some starting tutorials like the one Oracle gives:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/

Why does my function keep failing my JUnit test?

This is one of my classes that I am testing. It keeps failing the calculateVolume() method and I am not sure why.
package shape3D;
public class Sphere implements Cloneable {
private double myRadius;
private double myVolume;
private double mySurfaceArea;
private final static double pi = 3.14;
public static void main(String args[]){
Sphere sphere = new Sphere();
}
public double calculateVolume(){
myVolume = (4/3)*pi*(Math.pow(myRadius,3));
return myVolume;
}
public double calculateSurfaceArea(){
mySurfaceArea = ((4)*(pi)*(Math.pow(myRadius,2)));
return mySurfaceArea;
}
public double getSurfaceArea(){
return this.calculateSurfaceArea();
}
public double getVolume(){
return this.calculateVolume();
}
public void setRadius(double radius2){
myRadius = radius2;
}
public String toString(){
return "Volume: " + this.getVolume() + " Surface area " + this.getSurfaceArea();
}
public Sphere clone (){
Sphere p = new Sphere();
p.setRadius(myRadius);
return p;
}
}
Here is the JUnit test case I am using
public class sphereTest {
#Test
public void testSphere(){
shape3D.Sphere sphere = new shape3D.Sphere();
sphere.setRadius(6);
assertTrue(sphere.calculateSurfaceArea()== 452.16);
assertTrue(sphere.calculateVolume()== 904.32);
The calculateSurfaceArea() stuff passes fine but the volume is failing and I am not sure why.
The calculation
myVolume = (4/3)*pi*(Math.pow(myRadius,3));
Uses integer arithmetic: 4/3 evaluates to 1.
Change it to
myVolume = (4.0/3)*pi*(Math.pow(myRadius,3));
You're doing integer division when calculating the volume truncating the first term of the equation to 1. Replace
myVolume = (4 / 3) * pi * (Math.pow(myRadius, 3)); // 678.24
with
myVolume = (4 / 3.0) * pi * (Math.pow(myRadius, 3)); // 904.31
Due to floating point imprecision you will still need to allow for the difference between the expected & calculated values. You can use this version of assertEquals which allows a delta value to do the comparison - replace
assertTrue(sphere.calculateVolume()== 904.32);
with
assertEquals(sphere.calculateVolume(), 904.32, .02);
Quite aside from the 4/3 integer problem (which I failed to spot): It's not safe to compare two Java double values this way.
If you use assertEquals instead of assertTrue then you might see the problem. I'm betting that it's calculating 4/3 first, then truncating it. And it'll still do this even if you make those into doubles.
Use the overload for assertEquals as mentioned in this question.

Categories