Why does double parameterised function accepts float and not vice versa? - java

I have encountered something strange today. The below code compiles unexpectedly and runs fine.
public class Test {
public static void func(double d) {
System.out.print("d : " + d);
}
public static void main(String[] args) {
float f = 10.0f;
func(f); // output: d : 10.0
}
}
But this one gives compilation error
public class Test {
public static void func(float f) {
System.out.print("f : " + f);
}
public static void main(String[] args) {
double d = 10.0d;
func(d);
}
}
Can somebody please explain this behaviour ?

Type promotion from float to double is safe as no data is lost and all float 4 bytes can fit into double 8 byes.
However the opposite, from double to float, always truncates the data as double 8 bytes can't fit into float 4 bytes. Compiler guards against doing this truncation accidentally by forcing the programmer to manually specify the type conversion.

double(8 byte) is a bigger data type than float(4 byte) so you can store float(4 byte) in double(8 byte) but you can't double in float. If you try to do that you'll get Possible loss of precision error.
So the following will give error.
float f = 120.55;
While this one don't
double d = 120.44f;

Related

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.

Strictfp returns different results on different systems

I'm using the following method on Windows 8 (Intel Atom Z3775):
public static strictfp void main(String args[])
{
float a = 0.000000002f;
float b = 90000300000000004f;
float c = a * b;
System.out.println(c);
}
which gives me: 1.80000592E8
When running
public strictfp void calculate()
{
float a = 0.000000002f;
float b = 90000300000000004f;
float c = a * b;
Toast.makeText(getApplicationContext(), c + "", Toast.LENGTH_LONG).show();
}
i get: 1.8000059E8
Why do they differ? Am I using strictfp wrong?
You have confirmed that printing the hex representation of the floats shows that the values are the same:
String.format("%08x", Float.floatToIntBits(c))
This means that there is a difference in the implementation of how a float is converted to a String.
Notice that the OpenJDK implementation of java.lang.Float.toString(float) invokes a method from sun.misc.FloatingDecimal - i.e. it is a JDK-specific implementation.
You'd need either:
To ensure that you always run the code using the same implementation
To provide your own implementation which always produces the same result
To specify a shorter format, so that the strings are the same to that many decimal places.
Well, the displaying method certainly differs...

Java loss of precision with Heron's formula

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.

Wrong rounding with float division

I was doing some arithmetic program today and I got a real funny result passing the result of float division to a setter :
class A {
Float f;
setF(Float f) {
this.f=f;
print (f)
}
}
Long x=7L;
Long y=3L;
print (x/y.floatValue() )
a.setF(x/y.floatValue());
the result of the above pseudo program is something like this in the jdk 1.6
2.333333
2.0
any clue on where the round is performed?
Let me explain your first condition i.e. `x/y.floatValue()' what you are doing is:
long/ float because you are taking float value from variable y from floatValue() method so according to its implementation, you will get y = 3.0F.
/**
* Returns the value of this {#code Long} as a
* {#code float}.
*/
public float floatValue() {
return (float)value;
}
Your division will be 7L/ 3F or say 7/ 3.0 which will give you the result as 2.333333
Your second condition a.setF(x/y.floatValue()); will also result 2.333333 check if you missed something or post your whole code.
As you can see in console header I am using JDK1.6
It's a casting issue. Your x is still type long, whereas y.floatValue() is a float.
Both the divisor and the dividend need to be float or double to get what you want, so try for example, this:
Long x=7L;
Long y=3L;
System.out.println((float) x/(float) y);
result -> 2.3333333
This rounding down to 2.0 does not happen, there may be a problem with how you wrote the code from that pseudo-code
I tested with this implementation
public class A {
Float f;
void setF(Float f){
this.f=f;
System.out.println(f);
}
public static void main(String[] args) {
Long x=7L;
Long y=3L;
System.out.println(x/y.floatValue());
new A().setF(x/y.floatValue());
}
}
This is the result
2.3333333
2.3333333

Why does Java shows extra values after float calculation?

I have a very simple piece of code below which I think gives the wrong result from a user's perspective.
package com.test.sample;
public class Test {
public static void main(String[] args) {
float c,d;
c = (float) 12.47;
d = (float) 12.44;
d = c - d;
System.out.println("Hello the calculated value of a=" + d);
}
}
The output is
Hello the calculated value of a=0.030000687
But I want a=0.030000000 which is the perfect value.
Floating point arithmetic, what developers should know.
The JVM implements the IEEE-754 1985 floating point standard and it has its accuracy problem (since floating point numbers cannot precisely represent all real numbers).
If you seek accuracy, use java.math.BigDecimal object instead.
Update: This is how I took your example and used BigDecimal to achieve your expected result:
import java.math.BigDecimal;
/**
* #author The Elite Gentleman
*
*/
public class BigDecimalTest {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
BigDecimal a = new BigDecimal(Float.toString(12.47f));
BigDecimal b = new BigDecimal(Float.toString(12.44f));
BigDecimal c = a.subtract(b);
System.out.println(c);
}
}

Categories