Incorrect subtraction results: 3.999999, not 4 [duplicate] - java

This question already has answers here:
Adding and subtracting doubles are giving strange results [duplicate]
(2 answers)
Why do I see a double variable initialized to some value like 21.4 as 21.399999618530273?
(14 answers)
Closed 9 years ago.
So I narrowed down a bug in my application to java messing up a simple subtraction calculation. I can't figure out why exactly. Here is the bit of code:
for (double x = (((double)bdl.length())-1)/10; x > 0; x--) {
int count;
System.out.println("x = " + x);
if (x >= 1) {
System.out.println("X = " + x + " so count = 20");
count = (20);
} else {
count = (int)(x*20);
System.out.println("X = " + x + " so count = "+count);
}
}
The variable bdl is just a JSONArray, which I am only concerned with its length at this point. As bdl comes in initially it has length 15, so x will equal 1.4 . The first time through the loop the first println says "X = 1.4 so count = 20" which is correct. The second time through however when x should = 0.4, it instead says "X = 0.3999999999999999 so count = 7". I understand that casting (x*20) to an int at that point and time will give me 7, but my question is Why is x not equal to 0.4 .

You're using a double, which is a floating-point number. This is not meant for presision, moreover, it is meant for speed and non-precision. So instead, you should be using an int, like this:
for (int x = ((bdl.length())-1)/10; x > 0; x--) {
This will keep your numbers precise.

Actually, your 'x' does equal 0.4, it's only a matter of precision.
All floating point comparison operations should be executed with a certain precision (delta or epsilon in some implementations).
Refer to this post.

Related

Java Math.sqrt function rounding down to zero [duplicate]

This question already has answers here:
Int division: Why is the result of 1/3 == 0?
(19 answers)
How to divide 1 by 25(1/25) and get result .04 in java [duplicate]
(4 answers)
Closed 1 year ago.
I am trying to write a function to check a T score value and populate half of a 5x5 array.
public void calcTScores()
{
double temp = 0;
double tempSp = 0;
int n = 24;
this.tScores = new String [5][5];
for (int i = 0; i< this.Headers.length; i++){
for (int j = 0; j<this.Headers.length; j++)
{
if(i < j)
{
tempSp += (n-1)*this.SD[i] * this.SD[i] + (n-1)*this.SD[j] * this.SD[j];
tempSp = tempSp/(n+n-2);
tempSp = Math.sqrt(tempSp);
temp = tempSp * Math.sqrt(0.0833);
System.out.println(Math.sqrt(1/12));
temp = ((this.Mean[i] - this.Mean[j])/temp);
if(temp > 2.25 || temp< -2.25)
{
this.tScores[i][j] = "Y";
}
else
{
this.tScores[i][j] = "N";
}
temp = 0;
tempSp = 0;
}
}
}
}
Any idea why Math.sqrt(0.0833) and Math.sqrt(1/12) would evaluate to different values?
The T score when I add the 1/24 and 1/24 value and take the sqrt keeps evaluating to zero but when I plug in the actual decimal it gives me the answer I would expect
Any ideas why this is occuring?
1/12==0 as per integer division
There's nothing wrong with Math.sqrt. You're passing it the number zero.
Math.sqrt(1/12)
1/12 is a division operation on two integers (namely, 1 and 12), so it's going to produce an integer result. 12 goes into 1 zero times, so the integer result is zero. Thus, your expression is
Math.sqrt(0)
Consider
Math.sqrt(1.0/12.0)
Math.sqrt(1/12d)
Cast 1/12 to a double by casting one operand to a double.

Trouble Computing Pi with Java [duplicate]

This question already has answers here:
Double division behaving wrongly
(4 answers)
Closed 7 years ago.
I have been trying for a few days to compute pi using the series expansion pi = 4(1-1/3+1/5-1/7... but whenever I use the code I have below, it returns 4.0.
public class Pi {
public static void main (String args[]) {
double pie = 0.0;
int max = 1000;
for (int x = 1 ; x < max ; x = x + 2) {
if (x % 4 == 1) {
pie+= 1/x;
} else if (x % 4 == 3) {
pie-=1/x;
}
}
System.out.println(4*pie);
}
}
In this, I am computing pie to a denominator below 1000. Pie is the variable that stores my value created for pie. At the end, it prints pi, but always returns 4.0.
Using the Debug feature in my IDE (Eclipse), I see the value of pie jumps to 4 from the initial value of 0, but then does not change for the rest of the times the program increments the value of x in the for loop, it does not do anything to pi.
You are performing integer division with 1/x, which always results in an int, truncating the true decimal value. 1/1 is 1, but 1 divided by anything larger is 0 in Java, so your result will always be 4.
Use a double literal to force floating-point division.
pie += 1.0 / x; // and pie -= 1.0 / x;
Alternatively, you can cast 1 to a double.
pie += (double) 1 / x; // and pie -= (double) 1 / x;
The problem is that you are performing integer division and adding the result to a double. x is an int and 1 is an int. When you divide an integer by an integer, you get back an integer. Hence what you're adding to pie is always an integer.
The first time you run the loop, you evaluate the expression 1/1, which returns just 1 (an integer) and assigns that value to pie. For everything else after, you get 0, which means that pie doesn't change. Hence when you finally print 4 * pie, you get 4.
There are a few options:
Use double everywhere.
Change pie += 1 / x; to pie += (1.0 / x); (and the same for the other one)
Cast 1 to double before adding to pie: pie += (double) 1 / x.
The problem is that you are making an integer division which returns less than zero. As an integer, the value will be rounded to zero instead. This adds zero to pie on each iteration.
What you need to do is to replace the literal integer ones, to literal floating point ones, like this
package cl.misc.pi;
public class Pi {
public static void main(String args[]) {
double pie = 0.0;
int max = 1000;
for (int x = 1; x < max; x = x + 2) {
if (x % 4 == 1) {
pie += 1.00 / x;
} else if (x % 4 == 3) {
pie -= 1.00 / x;
}
}
System.out.println(4 * pie);
}
}
As you see, I did replace pie += 1 / x for pie += 1.00 / x which now adds a floating point result to pie.
Result of this routine is 3.139592655589785

How does the following statement work?

int x = 10;
x += x++;
System.out.println(x);
why the answer of above statement is 20 ?
The operator += is an addition assignment operator. Like Alya said above, x += x++ is equivalent to x = x + x++, which in your case is x = 10 + 10. However, it's a very messy statement and I'll explain why towards the end of this post.
Now, you're probably thinking "Why is it 20 and not 21 (10 + 11) since you have the ++?" and that's valid. There's actually a difference between a post-increment and a pre-increment. x++ is the post-increment and will actually evaluate the value of x first and THEN increment x, while ++x is the pre-increment which will increment x and THEN evaluate the value of x.
For example, x = 10; System.out.println(x++); System.out.println(x); will print 10 and then print 11 because the first print line prints x and THEN performs the ++ calculation, making x 11 which the next line prints. Conversely, x = 10; System.out.println(++x); System.out.println(x); will print 11 on both print statements.
Going back to why I said x += x++; is very messy is because technically the ++ operator isn't performed in this case. x++ is technically the same as x=x+1 and remembering that x+=y is the same as x = x+y) , the line x += x++; is kind of like saying x = x + (x = x + 1); which is kind of weird looking because you do 2 assignment statements in one and won't actually "work how you want it". Back to your example int x = 10; x += x++; if you print x, you will get 20 even though you could look at it as: x is now the value of x + the value of x, then finally + 1 to it. But unfortunately, that's not how it works.
To solve your problem, if you change your code from a post-increment to a pre-increment, then it should work, ie: x+=++x; will print your 11 but I would argue the that's quite unreadable and a bit confusing. x+=x; x++; System.out.println(x); is easier to follow.
x++ will execute first. It returns x and then increments x by 1.
Finally, the += operator will add to x the return value of x++, which was 10.
Thus, x will be 20 and it will overwrite the changes to x by the statement x++.
So first x is initialized to be 10. Then the x++ has higher precedence so that gets carried out first. the "++" is a post-increment in this case (because it is after the variable as opposed to pre-increment which would be ++x). Post-increment means "first use the variable then increment it by one" so in this case it first uses x to be 10 then increments it to 11 after it is used. Then we look at the "+=" which is short hand for "x = x+x++". so we have x = 10+10 which = 20. If you were to carry this out again it would equal x = 20+20 = 40.
In this particular case, the x++ isn't necessary as x is reassigned the value after it is incremented each time.
int x = 10; x += x++;
will equal to x=x+x
where x++ mean use the x value then increament it , so it's value will be 10
so the result will equal 20
if you want to see the change of the x , see this example:
int x = 10;
int y = 10;
y +=x++;
System.out.println(y);
System.out.println(x);
will print :
y=20
x=11////////////according to x++ and without to overwrite it
//
// Shows how increments work.
//
int i = 0;
System.out.println(i);
i++; // Add one
System.out.println(i);
i += 2; // Add two
System.out.println(i);
i += 3; // Add three
System.out.println(i);
++i; // Add one
System.out.println(i);
i += i; // Added itself
System.out.println(i);
//
// Uses increments and assigns.
//
int v = 0;
v = i++; // Increment after value copy
System.out.println(v);
System.out.println(i);
v = ++i; // Increment before value copy
System.out.println(v);
System.out.println(i);
//Output
0 -
1
3
6
7
14
14
15
16
16
x+=x++ first assigns the value to x and then increments (post-increment)
x+=++x first increments then assign the value to x (pre increment)
there are two types of increments/decrements in programming
1. pre-increment/decrement
2. post-increment/decrement
In programming both of these have same operations but differ in there nature as they both used for increment or decrement; they can be written as,
x+=1; (increment by 1)
x-=1; (decrement by 1)
you can use a variable instead in the above cases as well

Can 0.999... be rounded to 1 when multiplying? [duplicate]

This question already has answers here:
Can 0.99999999999 be rounded to 1.0 when multiplying?
(2 answers)
Closed 6 years ago.
When multiplying a floating point number that is very close to 1 with an int > 0, can it ever be interpreted as 1.
That is, if Math.random() returns its highest possible result (which is 1 step below 1.0), will
(int)(Math.random() * 8)
be 8 or 7?
For a practical example, can this often-used construct give an index out of bounds error:
someArray[(int)(Math.random() * someArray.length)];
I'm specifically interested in answers for Java and ActionScript 3, but I suppose they all use the same rules for floating point arithmetic, and answers for any platform would be useful.
Update: Though I already accepted an answer, I'd still appreciate confirmation that this can't go wrong in ActionScript 3 either, since a colleague reporting that he saw it go wrong once is what partly prompted me to ask this question.
Because 8 is a power of 2, multiplying a float by it will never add or remove precision from the value unless you overflow. Multiplying by other numbers, and in particular floating point numbers (other than a negative power of 2, e.g. 0.25, 0.0625, etc.), will reduce precision.
Using Math.random in java (http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Math.html) the value can be greater than or equal to 0.0 and less than 1.0.
Using one test with value 0.999999 the value of (int)(Math.random() * 8) is 8. You can test the experiment using the next code
public static void main(String args[]) {
for (int i = 0; i <= 100; i++) {
double frac1=0.999999999999999999 ;
double frac=Math.random() ;
int integer=(int) (frac*8);
int integer1=(int) (frac1*8);
System.out.println( integer+"-"+frac);
System.out.println( integer1+"-"+frac);
}
}
But Math.random()*8 can return other values like 1,2,3,4,5,7 or 6 depends of the value returned for Math.random. You can test this running the sample code
Actually a quick exhaustive search can show that this cannot happen for any 32bit integer with floats:
public static void main(String[] args) {
int repr = Float.floatToIntBits(1f) - 1;
float val = Float.intBitsToFloat(repr);
for (long i = 1; i <= -(long)Integer.MIN_VALUE; i++) {
if ((int) (val * i) == i) {
System.out.println("FOUND VALUE: " + i);
}
if ((int) (val * -i) == -i) {
System.out.println("FOUND VALUE: " + -i);
}
if (i % 100000000 == 0) {
System.out.println("Done: " + (double)i/Integer.MAX_VALUE);
}
}
// nothing printed
}

java for-loop problem

I am making a Java program to calculate Simpson's rule for integrals. Here is the code I have. Notice the second column of numbers in the output values of count == 4,9,10,11. They are not numbers that I need, they do not follow the pattern. I need these numbers to be accurate. What is going on and how can I fix it?
public static void main(String[] args)
{
double totalS = 0.0;
int count = 0;
for(double i=0; i< 4; i += 0.4 )
{
count++;
totalS += Sfunction(i, count);
System.out.println(count + " " + i + " " + totalS);
}
}
public static double Sfunction(double f1, int count)
{
double value;
if (f1 == 0.0 || f1 == 4.0)
value = Math.cos(Math.sqrt(f1));
else if ((count % 2) == 1)
value = 2 * Math.cos(Math.sqrt(f1));
else
value = 4 * Math.cos(Math.sqrt(f1));
return value;
}
I get the output of:
1 0.0 1.0
2 0.4 4.226313639540303
3 0.8 5.478244888601832
4 1.2000000000000002 7.30884788480188
5 1.6 7.911122809972827
6 2.0 8.534897589034324
7 2.4 8.578100205110182
8 2.8 8.168723348285942
9 3.1999999999999997 7.736055200662704
10 3.5999999999999996 6.452869366954546
11 3.9999999999999996 5.620575693860261
Each time you go round your loop, you are compounding the error in the inexact addition of 0.4 to i.
Instead, use an integral value for the loop counter, and scale that to get a better approximation to the values:
for ( int count = 0; count < 10; ++count ) {
final double i = 0.4 * count;
System.out.println ( ( count + 1 ) + " " + i );
}
This will not eliminate the floating point error, but it will mean it is not increasing at each iteration. To remove the error from the output, format the output to a reasonable number of decimal places:
for ( int count = 0; count < 10; ++count ) {
final double i = 0.4 * count;
System.out.printf ( "%2d %.1f\n", ( count + 1 ), i );
}
This is a classic floating point problem. If you need accuracy in your decimals, you should be using BigDecimal
This is how floating point numbers work in computers.
You can round the display, but the representation underneath won't change. Use java.text.DecimalNumberFormat to round to two decimal places.
What you are seeing is a result of floating point precision error, the numbers aren't stored like you're probably thinking. You can round the answer to 1 decimal place to get rid of the error...but this is just a result of how doubles are stored in java.
There's some good reading on this topic over here: Why do simple math operations on floating point return unexpected (inaccurate) results in VB.Net and Python?
Your problem is that you are using floating point arithmetic which can only approximate values, but assuming you have infinite precision. You shouldn't do equality tests like this with floating point numbers:
if (f1 == 0.0 || f1 == 4.0)
Any equality test with a floating point number is a code smell. With a float you should always check if it lies within a certain range, for example in the range 3.9999 to 4.0001.
In this specific example though, you also handily have another parameter called count which is an int. You can do equality tests with that. Maybe you can test that instead.
try to print them with only one decimal digit:
System.out.printf("%.1f", Math.E); // prints 2.7
System.out.printf("%.2f", Math.E); // prints 2.72
System.out.printf("%.3f", Math.E); // prints 2.718
or even try to specify the keyword strictfp for your number crunching methods
From your loop condition, it looks like you don't want line 11 to be processed at all. I recommend you use an integer loop index and use it to compute the values you pass to Sfunction. The following should be the equivalent of what you have now (except it leaves out line 11).
double totalS = 0.0;
for( int i = 1; i <= 10; i++ )
{
double f1 = 0.4 * (i - 1);
totalS += Sfunction(f1, i);
System.out.println(i + " " + f1 + " " + totalS);
}
Your problem with print precision can be solved with DecimalFormat, as suggested in other answers.

Categories