The same (int)doubles round up and down in Java - java

I'm having the weirdest problem with my game in java. :|
I can get around it, so I will be able to continue on this game without a solution, but I just thought it was really weird.
It's a 2D Minecraft-ish (I know, I know, it's just for practice) game, and I'm trying to destroy blocks by clicking them, which is working, but not as expected.
mX = (x * blockWidth - screenWidth * blockWidth / 2 + blockWidth / 2 + e.getX()) / blockWidth;
mY = y - screenHeight / 2 + .5 + e.getY() / blockHeight;
These two lines should define the x and y coordinates of the block the mouse is currently hovering over. Filling in the same numbers will result in the same answer as the second formula is a shorter version of the first. However, the second one does not work, clicking a block in the upper half section will result in breaking the block above it. The only reason I can think of is that, in the mouseClicked() method, the (int) (which is required as you can't click on half coordinates) rounds the first one up and the second one down because of the .5 in it. I'm not sure, that's why I'm asking you. :)
Does anyone know what the cause of this might be? I prefer not to use the upper formula because I want it to be much simpler.

Java is doing some hidden casts. Depending on which variable is a double or an int, you might get unexpected results because some double values have been casted to ints. I would make sure all your variables are doubles.
Also, do not forget that floating points also have representation limitations, that can affect computation and computation results.
If you want to round your value, you can use:
Math.round(2.7);
if you want to "round up", you can use:
Math.ceil(2.7);
if you want to "round down", you can use:
Math.floor(2.7);

Related

How would you write 2𝑠^2(1 + square root of 2) in java?

I am trying to attempt to create a code block which calculates the area of a floor space with user input (in this case my scanner input variable is s), but the area isn't calculating properly. What would be the correct way to write out the formula? Below is what I currently have.
double sForArea = s * 2;
double floorArea = (Math.pow(sForArea, 2)*(1 + Math.sqrt(2)));
I don't think you've translated that formula correctly.
I'd guess it should look like this:
// assume s is some characteristic length
double floorArea = 2.0*s*s*(1.0 + Math.sqrt(2.0)));
Note: There's no need for Math.pow() here. Squaring a number just means multiplying it by itself.
Others have noted that you have some ambiguity in your written formula. It's not clear what the term in parentheses is supposed to be multiplying. I wrote it in the way that makes most sense. It keeps the units as length squared, as it must be for area.

Rebounding Object Off Wall / Reversing Velocity in Java

I have an object with velocity of -5 going towards a wall. When it hits the wall, I want it to get a velocity of 5, thus reversing directions and rebounding. However, when I run it, it is not working. I've used several variations, I guess I am making a syntactical error.
public void action(int t) {
setVY(-5); //works - no surprises sets velocity to -5
.
.
if(getY() <= 0 ) {
setVY(5); //THIS METHOD DOESN'T WORK
setVX(5); // works no surprises , ball goes right
hooks.setMessage("hits wall", 25); //no surprises
}
}
This does compile and run with no errors. The object now goes north and then veers north/east at 45 degrees.
This works. Although it does perhaps not work as you expect. Are you remembering to add the velocity to the position, before checking the position again? If not, getY() will still return 5, and it will flip the sign of yv again (so it's back the way it was). You can write a small unit test which confirms that this works.
Since your example is not functional, it's hard to say exactly what's wrong, but if you feed the algorithm with the correct data, it will flip the sign of the y velocity.
i'm sorry I can't comment on your question therefor I use the answering facility. Could you be more specific as to what is not working. Is you value for vy wrong or is the setter setVY not setting the right value to your object? Or is something different not working?
as Gilbert above mentioned: Why do you compare y to 5? Couldn't there be situations where y never is exactly 5 something a little bit smaller or larger than 5. E.g. the object is already a small fraction "inside" the wall and you still want the object to change direction and rebound...
Bye,
Markus

Normalized Iteration Count does not work. What am I doing wrong?

As you can see from the title, I'm busy programming a little programm for visualizing fractals in Java. Anybody who deals with fractals will come to the point where he/she searches for a solution to get these stupid "bands" away, when you just colour a pixel by the number of iterations it took to escape.
So I searched for a more advanced colouring algorithm, finding the "normalized iteration count". The formula I'm using is:
float loc = (float) 1 - Math.log(Math.log(c.abs())) / Math.log(2);
Everybody on the Internet is so happy about this algorithm, everybody uses it, everbody gets great results. Except me. I thought, this algorithm should provide a float between 0 and 1. But that doesn't happen. I did some calculations and came to the conclusion, that this algorithm only works for c.abs() >= Math.E && c.abs() <= Math.exp(2) (that is Math.E * Math.E).
In numbers this means, my input into this equation has to be between about 2.718 and 7.389.
But a complex number c is considerd to tend towards infinity when its magnitude gets greater than 2. But for any Input smaller than Math.E, I get a value greater than one. And for any number greater than Math.exp(2), it gets negative. That is the case if a complex number escapes really fast.
So please tell me: what am I doing wrong. I'm desperate.
Thanks.
EDIT:
I was wrong: the code I posted is correct, I just
1. used it the wrong way and so it didn't provide the right output.
2. had to set the bailout value of the mandelbrot/julia algorithm to 10, otherwise I would've got stupid bands again.
Problem solved!
As you've already discovered, you need to increase the bailout radius before smoothing will look right.
Two is the minimum length that a coordinate can have such that when you square it and add the initial value, it cannot result in a smaller length. If the previous length was 2.0, and you squared it, you'd have a length of 4.0 (pointing in whichever direction), and the most that any value of c could reduce that by is 2.0 (by pointing in precisely the opposite direction). If c were larger than that then it would start to escape right away.
Now, to estimate the fractional part of the number of iterations we look at the final |z|. If z had simply been squared and c not added to it, then it would have a length between 2.0 and 4.0 (the new value must be larger than 2.0 to bail out, and the old value must have been less than 2.0 to have not bailed out earlier).
Without c, taking |z|'s proportional position between 2 and 4 gives us a fractional part of the number of iterations. If |z| is close to 4 then the previous length must have been close to 2, so it was already close to bailing out in the previous iteration and the smoothed result should be close to the previous iteration count to represent that. If it's close to 2, then the previous iteration was further from bailing out, and so the smoothed result should be closer to the new iteration count.
Unfortunately c messes that up. The larger c is, the larger the potential error is in that simple relationship. Even if the old length was nearly at 2.0, it might have landed such that c's influence made it look like it must have been smaller.
Increasing the bailout mitigates the effect of adding c. If the bailout is 64 then the resulting length will be between 64 and 4096, and c's maximum offset of 2 has a proportionally smaller very impact on the result.
You have left out the iteration value, try this:
float loc = <iteration_value> + (float) 1 - Math.log(Math.log(c.abs())) / Math.log(2);
The iteration_value is the number of iterations which yielded c in the formula.

How to handle multiplication of numbers close to 1

I have a bunch of floating point numbers (Java doubles), most of which are very close to 1, and I need to multiply them together as part of a larger calculation. I need to do this a lot.
The problem is that while Java doubles have no problem with a number like:
0.0000000000000000000000000000000001 (1.0E-34)
they can't represent something like:
1.0000000000000000000000000000000001
Consequently of this I lose precision rapidly (the limit seems to be around 1.000000000000001 for Java's doubles).
I've considered just storing the numbers with 1 subtracted, so for example 1.0001 would be stored as 0.0001 - but the problem is that to multiply them together again I have to add 1 and at this point I lose precision.
To address this I could use BigDecimals to perform the calculation (convert to BigDecimal, add 1.0, then multiply), and then convert back to doubles afterwards, but I have serious concerns about the performance implications of this.
Can anyone see a way to do this that avoids using BigDecimal?
Edit for clarity: This is for a large-scale collaborative filter, which employs a gradient descent optimization algorithm. Accuracy is an issue because often the collaborative filter is dealing with very small numbers (such as the probability of a person clicking on an ad for a product, which may be 1 in 1000, or 1 in 10000).
Speed is an issue because the collaborative filter must be trained on tens of millions of data points, if not more.
Yep: because
(1 + x) * (1 + y) = 1 + x + y + x*y
In your case, x and y are very small, so x*y is going to be far smaller - way too small to influence the results of your computation. So as far as you're concerned,
(1 + x) * (1 + y) = 1 + x + y
This means you can store the numbers with 1 subtracted, and instead of multiplying, just add them up. As long as the results are always much less than 1, they'll be close enough to the mathematically precise results that you won't care about the difference.
EDIT: Just noticed: you say most of them are very close to 1. Obviously this technique won't work for numbers that are not close to 1 - that is, if x and y are large. But if one is large and one is small, it might still work; you only care about the magnitude of the product x*y. (And if both numbers are not close to 1, you can just use regular Java double multiplication...)
Perhaps you could use logarithms?
Logarithms conveniently reduce multiplication to addition.
Also, to take care of the initial precision loss, there is the function log1p (at least, it exists in C/C++), which returns log(1+x) without any precision loss. (e.g. log1p(1e-30) returns 1e-30 for me)
Then you can use expm1 to get the decimal part of the actual result.
Isn't this sort of situation exactly what BigDecimal is for?
Edited to add:
"Per the second-last paragraph, I would prefer to avoid BigDecimals if possible for performance reasons." – sanity
"Premature optimization is the root of all evil" - Knuth
There is a simple solution practically made to order for your problem. You are concerned it might not be fast enough, so you want to do something complicated that you think will be faster. The Knuth quote gets overused sometimes, but this is exactly the situation he was warning against. Write it the simple way. Test it. Profile it. See if it's too slow. If it is then start thinking about ways to make it faster. Don't add all this additional complex, bug-prone code until you know it's necessary.
Depending on where the numbers are coming from and how you are using them, you may want to use rationals instead of floats. Not the right answer for all cases, but when it is the right answer there's really no other.
If rationals don't fit, I'd endorse the logarithms answer.
Edit in response to your edit:
If you are dealing with numbers representing low response rates, do what scientists do:
Represent them as the excess / deficit (normalize out the 1.0 part)
Scale them. Think in terms of "parts per million" or whatever is appropriate.
This will leave you dealing with reasonable numbers for calculations.
Its worth noting that you are testing the limits of your hardware rather than Java. Java uses the 64-bit floating point in your CPU.
I suggest you test the performance of BigDecimal before you assume it won't be fast enough for you. You can still do tens of thousands of calculations per second with BigDecimal.
As David points out, you can just add the offsets up.
(1+x) * (1+y) = 1 + x + y + x*y
However, it seems risky to choose to drop out the last term. Don't. For example, try this:
x = 1e-8
y = 2e-6
z = 3e-7
w = 4e-5
What is (1+x)(1+y)(1+z)*(1+w)? In double precision, I get:
(1+x)(1+y)(1+z)*(1+w)
ans =
1.00004231009302
However, see what happens if we just do the simple additive approximation.
1 + (x+y+z+w)
ans =
1.00004231
We lost the low order bits that may have been important. This is only an issue if some of the differences from 1 in the product are at least sqrt(eps), where eps is the precision you are working in.
Try this instead:
f = #(u,v) u + v + u*v;
result = f(x,y);
result = f(result,z);
result = f(result,w);
1+result
ans =
1.00004231009302
As you can see, this gets us back to the double precision result. In fact, it is a bit more accurate, since the internal value of result is 4.23100930230249e-05.
If you really need the precision, you will have to use something like BigDecimal, even if it's slower than Double.
If you don't really need the precision, you could perhaps go with David's answer. But even if you use multiplications a lot, it might be some Premature Optimization, so BIgDecimal might be the way to go anyway
When you say "most of which are very close to 1", how many, exactly?
Maybe you could have an implicit offset of 1 in all your numbers and just work with the fractions.

Splitting a swing control into equal parts

I know this is gonna be a stupid question.
Pardon me as a n00b into CS
I have a new swing component that inherits from JComponent.
I am trying to paint lines on its surface to show that the lines split the control into equal parts. The code looks like
int spc;
spc = (int) Math.round((this.ZBar.getWidth() / this.ZBar.getModel().getModelSize()));
for (int i = 0; i <= this.ZBar.getModel().getModelSize(); i++) {
g.drawLine(i * spcing, 0, i *, this.ZBar.getHeight());
}
this.ZBar.getModel().getModelSize(); gives out number of parts to split into.
However, in some cases there is some more space left on the right most end of my component. I guess it is gue to the Type conversion done by Math.round. How can I solve this ??
It is because that division is a int type divide. For example:
5 / 2 == 2
Math.round is doing nothing here. It is already being rounded (as Math.floor instead).
To get your intended effect, cast the int to a double before the division:
(double)5 / 2 == 2.5
Or in your specific case:
spc = (int) Math.round(((double)this.ZBar.getWidth() / this.ZBar.getModel().getModelSize()));
The code you posted will not compile due to syntax errors, but I see no immediate problems with your approach. You said that the problem shows up intermittendly. This suggests the problem might lay with the way swing does refreshing, and how you handle that in your code. Try reading up on that.
Thank you very much for the reply.
Solved this.
I have made all those integer mess to double.
Then used Java2D package to handle doubles.
Line2D class support creation using double parameters.

Categories