Wrong rounding with float division - java

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

Related

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

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;

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

implementation formula volume of a sphere with Java and JUnit?

I have to make an implementation to calculate volume of a sphere to be checked with JUnit test, but there are some errors. The formula is correct, but when I test it, it doesn't work :
class VolumeSphere.java
public class VolumeSphere {
public static double volsph(double j) {
double volume;
double const = 1.33;
double phi = 3.14;
volume = const * phi * (j * j * j);
return volume;
}
}
and then this the test file :
VolumeSphereTest.java
import junit.framework.*;
public class VolumeSphereTest extends TestCase {
public VolumeSphereTest(String name) {
super(name);
}
public void testSimple() {
assertEquals(33.4096, VolumeSphere.volsph(2.0));
}
}
when I run the JUnit test, it's said "Expected: (33.4096) but was: (33.4096000005)."
So, what should I do? Thankyou in advance for the help!
The problem is that 33.4096 isn't exactly represented by a double, nor is 1.33, and nor is 3.14. Moreover, the multiplication introduces its own errors. Therefore, the assertEquals needs to be replaced by something that basically means "assert that the value is very close to what we expect".
JUnit has assertEquals(expectedValue, actualValue, errorPermitted) for comparing doubles, which is what you should use here.
In general, double is a poor choice of data type for doing exact arithmetic with numbers expressed as decimals, because it stores binary representations of numbers. If you want accuracy with exact decimals, use BigDecimal instead.
const is a keyword and can't be a name of a variable - pick a different name for your variable.
The problem is that the answer isn't exactly the value you let the JUnit test compare to. The answer is 33.409600000000005 instead of 33.4096. To remedy this, you could use assertEquals(33.4096, VolumeSphere.volsph(2.0), 0.0001);.
This will allow all answers within a difference of 0.0001 around 33.4096. Therefor in this case it will allow 33.4095 to 33.4097.
Also, instead of using double phi = 3.14, you could use Math.PI, which inserts the more significant value of constant pi.

After a few seconds, a method takes longer to execute

I have this method:
public double sineWave(double t)
{
return amplitude==0?0:Math.sin(t * frequency * Math.PI*2 + phase) * amplitude;
}
It is called by another method in another class to generate a sample of a simple sine wave, which is then added in a buffer to send to the sound card. t is the time. For some reason, the more the application calls this method, the slower it gets. It just makes no sense, after 15 seconds it's slow enough to use a full core of my CPU and make the audio stutter.
I'm 100% sure it's this piece of code, because if I replace it with a return 0, the time it takes to run it (measured with System.nanotime()) is constant.
Why is this happening? Is there something I can do to fix this?
From the information here - while it is not clear how big your buffer is, you are incrementing t with each iteration. Assuming your frequency is quite high, you are increasing the Sin() argument with each iteration.
Have checks to see if the argument is constantly increasing to a very high value.
A quick and dirty test shows that Sin performance goes down -
public class SinTest {
public static void main(String args[]) {
long angle = Long.parseLong(args[0]);
long startTime = System.nanoTime();
for(long l=0L; l<=1000000L; l++) {
Math.sin(angle);
}
long estimatedTime = System.nanoTime() - startTime;
System.out.println(estimatedTime);
}
}
$ java SinTest 100000
29181000
$ java SinTest 10000000
138598000
Please give no points, so the solution would be given the answer of #mk:
public double sineWave(double t)
{
final double TAU = Math.PI *2;
double a = t * frequency;
a -= (long)a;
return amplitude==0?0:Math.sin(a * TAU + phase) * amplitude;
}
i solved the problem with a lookup table:
private static final int LUT_SIZE=1000000;
private static double[] sineLookupTable=new double[(int)(Math.PI*2*LUT_SIZE)];
static{
for(double i=0;i<sineLookupTable.length;i++){
sineLookupTable[(int)i]=Math.sin(i/(double)LUT_SIZE);
}
}
private static double sinLUT(double t){
return sineLookupTable[(int) (((long) Math.floor((t%Math.PI*2)*LUT_SIZE))%sineLookupTable.length)];
}
public double sineWave(double t) {
return amplitude==0?0:sinLUT(t * frequency * Math.PI*2 + phase) * amplitude;
}
it works... kinda, only problem is that i get a lot of distorsion on high frequencies. is there some interpolation method you can suggest?
Current versions of the Java framework will attempt to mod-reduce the argument to Math.sin using a mathematically-perfect value of 2π, rather than the value Math.PI*2. For code such as yours, this means the code will take longer and yield less accurate results than if mod reduction had been performed using the same scale factor as was used in multiplication (i.e. Math.PI*2). To get good accuracy and speed, you should perform modulo reduction before doing the multiplication, using something like:
double thisSpin = t * frequency;
thisSpin -= (thisSpin - Math.Floor(thisSpin)) * 8.0; // value of 0-7.9999=one rotation
switch((int)(thisSpin*8.0))
{
case 0: return Math.sin( thisSpin * (Math.PI/4.0));
case 1: return Math.cos((2-thisSpin) * (Math.PI/4.0));
case 2: return Math.cos((thisSpin-2) * (Math.PI/4.0));
case 3: return Math.sin((4-thisSpin) * (Math.PI/4.0));
case 4: return -Math.sin((thisSpin-4) * (Math.PI/4.0));
case 5: return -Math.cos((6-thisSpin) * (Math.PI/4.0));
case 6: return -Math.cos((thisSpin-6) * (Math.PI/4.0));
case 7: return -Math.sin((8-thisSpin) * (Math.PI/4.0));
default: return 0; // Shouldn't be possible, but thisSpin==8 would be congruent to 0
}
That will ensure that neither sin nor cos is ever used with an argument greater than π/4, which is according to the documentation the point where Java switches to using slow and counterproductive range reduction.

call method that rounds java

OK so I can't understand why it says the method isn't being used locally.... The private String formatNumber() method is saying this.
Basically what I need to do is have a method that returns the circumference
- another method that rounds numbers to 2 decimal places and returns a string
- and another method that returns the formatted version of circumference...
It's not hard to see what I'm trying to do, but it gives me the above stated error and I can't figure it out.
//figures out circumference
public double getCircumference(){
circumference = 2 * Math.PI * radius;
return circumference;
}
//takes string and turns back into a double
public double getFormattedCircumference(){
double x = Double.parseDouble(format);
return x;
}
//this method is giving the error of not being used locally...
//method takes double and turns to string so that it can be formatted and it
has to be a string
private String formatNumber(double x){
x = circumference;
NumberFormat number = NumberFormat.getNumberInstance();
number.setMaximumFractionDigits(2);
String format = number.format(x);
return format;
}
You've declared the private method but you've not used it in your current code anywhere and so the compiler is warning you of this (check your program to see if you're calling this method anywhere).
Incidentally, what you're seeing is a warning not an error. Your code should still compile, and the program will still run (if there are no errors present).
Edit 1
You've a serious problem with the method, and maybe more than one, in that it takes in a double parameter and then promptly discards it. Why? If you want to format the number that is passed in as a parameter, then you don't want to discard that parameter. Also, do you want to make this method public so that it can be called by objects outside of this class? Also, will the method have state or will it be stateless? Will it use the fields of the class, or will it only format the number passed into it. If the latter, than it should be a static method.
I got it all figured out. I was making it harder than it actually was.
//figures out circumference
public double getCircumference(){
circumference = 2 * Math.PI * radius;
return circumference;
}
public String getFormattedCircumference(){
return formatNumber(getCircumference());
}
//formats to two decimal places.
private String formatNumber(double x){
NumberFormat number = NumberFormat.getNumberInstance();
number.setMaximumFractionDigits(2);
String format = number.format(x);
return format;
}

Categories