programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
• Campbell Ritchie
• Tim Cooke
• Paul Clapham
• Devaka Cooray
• Bear Bibeault
Sheriffs:
• Junilu Lacar
• Knute Snortum
• Liutauras Vilda
Saloon Keepers:
• Ron McLeod
• Stephan van Hulst
• Tim Moores
• Tim Holloway
• Piet Souris
Bartenders:
• salvin francis
• Carey Brown
• Frits Walraven

# Math class - Calculating points on a circle using radius

Greenhorn
Posts: 14
1
I have to print points on a circle in increments of -0.1, but when I use a number larger than 1.3, the list stops at 0.1 larger than negRadius, and I don't know why. (Assume the center is (0,0))

Marshal
Posts: 68857
275
You aren't clear about what you need to print out. What is increasing by 0.1 at a time?
Are you aware of the Math#hypot method, which is actually intended for calculating the radius of a circle for polar coordinates. You will probably find it simpler to use than calculating Pythagoras the long way.
You know that the locus of a circle can be defined as (rsinθ, rcosθ)?

You know that incrementing a double by 0.1 is a notorious example of the imprecision of floating‑point arithmetic? You can find the exact value of the double 0.1 here, and you can see it is very slightly greater than 0.1. So it is obvious that your loop will run not more than twenty times. Try it. It will confidently run twenty‑one times

Campbell Ritchie
Marshal
Posts: 68857
275
Avoid Math.pow(x, 2)
You will usually find x * x gives faster performance and is more precise.

Damien Sky
Greenhorn
Posts: 14
1
It is x (the x-coordinate of the point on the circle) that is decreasing by 0.1. I do not even know what a locus is.

I don't know of Math#hypot, but would it be useful since I'm calculating the y-value, not the hypotenuse?

Also, I have to use Math.pow(x, 2) because the lesson this assignment is for is a lesson on the Math class, and I have been told that if I just do things like x*x, I am "doing the computer's work for it" and I shouldn't be doing that. I will have points deducted if I do that.

The problem is not with that, it's just that it stops early. I was given a screenshot of what it should look like when it's run for radius = 1, and my values matched it.

I just figured out something else. I have this problem between radius values of 1.4 and 4.6, but values less than 1.4 or greater than 4.6 are fine. Even 10 worked fine.

I could use if(radius >= 1.4 && radius <= 4.6) to fix this, but I want to know why this problem is happening and if there is a different way to solve it.

Bartender
Posts: 10777
71

Damien Sky wrote:It is x (the x-coordinate of the point on the circle) that is decreasing by 0.1.

No it isn't, because a coordinate involves two numbers.

My suggestion is that you give us the requirements exactly as they were given to you, because "decreasing by 0.1" could mean almost anything.

Question: Is the idea that you should plot 10 different points on the same circle, or 10 similar points on different circles? Because by calling your control field "radius" you're suggesting the latter.

And if it's the first, should they be regularly spaced "around the clock"? If so, a better name for your control variable might be "perimeter".

Inquiring minds want to know...

Winston

Bartender
Posts: 1464
32
• 1
To understand what's going wrong, you need to eliminate the parts of your program that don't make any difference to what you are asking about. Once done, you would have something like this:

By golly, when I run that, it stops before x reaches 1.4, too. Here's the output:

Now, ignore all the helpful tips you've gotten here about the Math class for the moment (and about coordinates being two numbers [Winston, where did you get that idea? ]). As we can see, your problem doesn't depend on circles, computing the other coordinate of a point on a circle, or the Math class at all. Instead, something is making your loop stop early. It's as though x drops below -1.4 one step too soon. Could that really be happening?

Here's the output:

No surprises there, right? Yet, what Campbell told you is correct:

...incrementing a double by 0.1 is a notorious example of the imprecision of floating‑point arithmetic...

He's right about that, yet our output seems to show no imprecision at all. How could Campbell be right when our output shows perfect precision? Well, let's go the other way and ask printf to show no decimal places:

Here's the output:

Whoa! We sure didn't change how we compute x at each pass through the for loop, yet it only seems to have three different values, each of which gets used more than once! How can that be? The answer is, it can't be. x actually is changing on each pass through the loop. Why doesn't it seem to change on our output? Because printf is rounding it to the number of decimal places we asked for which, in the last case, was zero. Rounded to zero places, a number like "1.1" is printed as "1." So is a number like "1.22," or even "1.20001." With that in mind, let's ask for a lot of decimal places:

You run this one yourself. The output is probably going to surprise you but, once you understand it, you will know the answer to your original question.

Good luck.

Winston Gutkowski
Bartender
Posts: 10777
71

Stevens Miller wrote:Now, ignore all the helpful tips you've gotten here about the Math class for the moment (and about coordinates being two numbers [Winston, where did you get that idea? ]).

Erm, from Maps? Wiki admittedly says that it can be "one or more"; but I can't see how that would work for a circle (which is a 2-D shape) without an agreed centre, radius and "North". And even then, wouldn't it simply be a "bearing" or angle?

I know I'm not a Maths expert, but please tell me where I've gone wrong.

Winston

Stevens Miller
Bartender
Posts: 1464
32

Winston Gutkowski wrote:

Stevens Miller wrote:Now, ignore all the helpful tips you've gotten here about the Math class for the moment (and about coordinates being two numbers [Winston, where did you get that idea? ]).

Erm, from Maps? Wiki admittedly says that it can be "one or more"; but I can't see how that would work for a circle (which is a 2-D shape) without an agreed centre, radius and "North". And even then, wouldn't it simply be a "bearing" or angle?

I know I'm not a Maths expert, but please tell me where I've gone wrong.

Winston

Do you mean "Maps," as in "graphical representations of things like terrain," or are you referring to some Java class called Maps? Anyway, where you went wrong was in saying,

a coordinate involves two numbers.

A coordinate is a single number. A set of them (typically at least two, but one alone is okay) constitute "coordinates." In Damien's case, he is correct to the effect that his loop variable is the x-coordinate in the xy-plane containing his circle. An x-coordinate and a y-coordinate are each a single number. Together, in the xy-plane, they are a pair of coordinates that identify a unique point in the plane. More generally, any number of coordinates can identify a unique point in any n-dimensional space. (There are some boringly complicating extensions to this: for example, a lot of code behind 3-D graphics is written to handle four-coordinate vectors of "homogenous" coordinates, in the form of [x, y, z, w], where the point in 3-space is identified by the three coordinates (x/w, y/w, z/w). Believe it or not, this actually simplifies perspective transformations, since a four-coordinate vector can be multiplied by a 4x4 matrix, which can contain any number of rotations, translations, enlargements, and perspective transforms, all composited upon one another, to put a canonical object into a 3-D scene.)

Damien is trying to compute the y-coordinate of a circle as a function defined on a range of x-coordinate values (actually, since circles aren't functions along any axis in the cartesian plane, he's correctly computing pairs of y-coordinates from each x-coordinate, which, when he solves the problem he's having, may lead him to yet another problem, involving the taking of square roots of negative numbers, but not if he's careful). But, Damien's problem is entirely captured in Campbell's warning about the imprecision of floating-point variables. I'm just trying to help Damien see his problem for what it is, which has nothing to do with circles, powers of two, or what a coordinate is.

Winston Gutkowski
Bartender
Posts: 10777
71

Stevens Miller wrote:A coordinate is a single number.

Aha. My first mistake. I presume then it's called a 'coordinate' because there's a second number involved; maybe the 'origin'?

An x-coordinate and a y-coordinate are each a single number. Together, in the xy-plane, they are a pair of coordinates that identify a unique point in the plane. More generally, any number of coordinates can identify a unique point in any n-dimensional space.

Yeah, that bit I knew (kind of).

There are some boringly complicating extensions to this: for example, a lot of code behind 3-D graphics is written to handle four-coordinate vectors of "homogenous" coordinates, in the form of [x, y, z, w], where the point in 3-space is identified by the three coordinates (x/w, y/w, z/w). Believe it or not, this actually simplifies perspective transformations, since a four-coordinate vector can be multiplied by a 4x4 matrix, which can contain any number of rotations, translations, enlargements, and perspective transforms, all composited upon one another, to put a canonical object into a 3-D scene.

Interesting. I can see I'm going to have to do a lot more reading on this.

Damien is trying to compute the y-coordinate of a circle as a function defined on a range of x-coordinate values (actually, since circles aren't functions along any axis in the cartesian plane, he's correctly computing pairs of y-coordinates from each x-coordinate...

Oh, OK. So if, for sake of argument, x = 1.0 is the "top" of the circle, he wants to know the y values as he goes linearly down the x axis in steps of 0.1 to 0, which can then be mirrored for the lower half of the semicircle.

Now I get it (I think). Tell me if I'm wrong.

Winston

Damien Sky
Greenhorn
Posts: 14
1
I created a double "increment" and changed the code to this:

It now shows the final x value and gives it y value as 0, but also gives y = 0 when x = negRadius + 2 * increment. How would I fix that?

Winston Gutkowski
Bartender
Posts: 10777
71

Damien Sky wrote:I created a double "increment" and changed the code to this:

I think you're concentrating a bit too much on the code at the moment, and not on WHAT you need to do. Sorry for steering you wrong on the 'coordinates', but here I do know what I'm taking about (promise ).

1. Without going into the internals of floating-point numbers (eg, double) in detail, there is only one class of value that you can be sure will be held exactly: whole numbers (and there are limits for those too).
Most other values - and certainly most that are returned by functions - will be approximations.

One such value in particular is 0.1 (which is very likely why it was given to you for this problem). A double simply cannot hold 0.1 as an exact value - and for this reason, they tend to make very poor control values for loops. On the other hand:

int one = 1;
double x = one / 10.0;
(Note: the '.0' is important; I'll leave you to discover why)

will set x to the closest value to 0.1 it's possible for a double to hold. Now, how do you think you might be able to use that knowledge to re-tool your loop?

2. StopCoding (←click).
You plainly know roughly what you want to do, but you haven't thought it through completely; which is why you're now having to resort to 'tweaking' to get it right. Write down exactly what you want to do, in detail and in English before you write any Java code. For one thing, it helps you understand the problem better; and for another, it makes the whole business of coding very much easier.
It's a pain when you're just dying to see results but believe me, it works. It's also a very good habit to get into for later on because - trust me - these problems are only going to get harder.

Winston

Saloon Keeper
Posts: 3888
154
I was just having a look at this topic, and it seems strange that, as far as I can tell, no one has given
OP a clue on how to avoid these floating point inaccuracies.

Winston is right, use integer arithmatic. Suppose you have some segment [a, b], for which you want to
calculate some evenly spaced sequence [x(0) = a, x(1), x(2), .., x(n) = b].

Then the formula x(k) = a * (n - k) / n + b * k / n does miracles.

For instance (I've choosen n such that the increment = 0.1):

Edited: put the square root in

Stevens Miller
Bartender
Posts: 1464
32
• 1
Piet, the reason I haven't gone to the step you have is that the OP didn't seem to know that floating point numbers tend to be imprecise, nor why. His latest work-around is still somewhat problematic, but shows an improved understanding. We can just write a working version of his code for him, but, as I understand it, that's against local policy. Your solution works, but hides the nature of the problem, which I hope he will fully comprehend before this thread is resolved.

Piet Souris
Saloon Keeper
Posts: 3888
154
In principle I agree. However, seeing that after your long reply, the discussion went
from homogenous coordinates to stop coding, I thought that a shortcut could
speed up things. Well, I wonder what OP has to say.

Stevens Miller
Bartender
Posts: 1464
32

Winston Gutkowski wrote:Oh, OK. So if, for sake of argument, x = 1.0 is the "top" of the circle, he wants to know the y values as he goes linearly down the x axis in steps of 0.1 to 0, which can then be mirrored for the lower half of the semicircle.

Now I get it (I think). Tell me if I'm wrong.

Winston

Pretty close. He wants to go from 1.0 to -1.0 (the "top" of the circle is at x=0.0). My whole reason for being a pest about coordinates and the Math class is simply that his problem has nothing do with circles or any related complicating topics. He's just coping, as many of us have, with the fact that subtracting 0.1 from 1.0, twenty times, does not yield -1.0 as his final result. I just wanted him to focus on that, and that alone, until he came to grips with the rather mind-bending fact that computers are crap at doing sums. (Well, it was mind-bending to me, when I had to come to grips with it.)

Stevens Miller
Bartender
Posts: 1464
32

Piet Souris wrote:In principle I agree. However, seeing that after your long reply, the discussion went
from homogenous coordinates to stop coding, I thought that a shortcut could
speed up things. Well, I wonder what OP has to say.

Hey, my words are golden. You should be grateful when I'm prolix .

Actually, Winston's oft-given advice to stop coding (I tend to word that as, "keep your hands where I can see them and step away from the mouse"), is applicable here. Damien needs to understand the nature of floating point numbers to know why his loop was working the way it was. Heh, when I first coped with this (which was in 1975), knowing how floating-point numbers were actually encoded was a kind of rite of passage for programmers. Today, Java's philosophy, that native types must be opaque, seems somewhat in conflict with knowing why integer types are (within their ranges) always exact, but floating types cannot be similarly trusted. My beloved "Core Java" introduces floating-point numbers by describing floats and doubles in terms of how many "signficant digits" of precision they have. It then goes on to warn against using them in "financial" calculations, because of round-off (even explaining that neither a float nor a double can exactly represent the value 1/10). But, taken as a whole, a beginner could end up thinking, "Well, I'm computing the coordinates of points on a circle, not running a bank, so this isn't a financial calculation, and I've got a circle of radius 1.0, with steps of only 0.1, so six significant digits will certainly be enough for me." Indeed, if Java were to use binary-encoded decimal (something I would not support, of course) as the internal format of its floats, Damien's first program would have worked fine, and floats would be just as opaque as they are now. It's because they use the internal format that they do, that he is having a problem, and that opacity may, however unintentionally, be part of the reason.

Campbell Ritchie
Marshal
Posts: 68857
275

Stevens Miller wrote: . . . "keep your hands where I can see them and step away from the mouse" . . .

Hahahahahahaha! Do you have to hold a Colt .45 as you say that?

Today, Java's philosophy, that native types must be opaque, seems somewhat in conflict with knowing why integer types are (within their ranges) always exact, but floating types cannot be similarly trusted. . . .

Or maybe that two's complement arithmetic and IEEE 754 numbers were well‑known before Java was developed and they took it for granted people knew how binary arithmetic works?

Stevens Miller
Bartender
Posts: 1464
32

Campbell Ritchie wrote:

Stevens Miller wrote: . . . "keep your hands where I can see them and step away from the mouse" . . .

Hahahahahahaha! Do you have to hold a Colt .45 as you say that?

Heavens, no! My weapon of choice is far more persuasive:

Today, Java's philosophy, that native types must be opaque, seems somewhat in conflict with knowing why integer types are (within their ranges) always exact, but floating types cannot be similarly trusted. . . .

Or maybe that two's complement arithmetic and IEEE 754 numbers were well‑known before Java was developed and they took it for granted people knew how binary arithmetic works?

Man, if the people you hang with know about such things, I'd like to spend more time with them myself. For a newcomer to coding, I think that might be somewhat abstruse subject matter.

To pursue that a bit, though: is it safe to assume that opaque types will never change internally? I am guessing the language spec calls for a format, but I really don't know and, even if it does, does it say the format will never change? I was kind of embarrassed, when I started learning Java, to realize I didn't even know what "opaque" meant, in the context of a programming language. As I understand it now, however, the virtue of opacity is that I am neither supposed to care nor know how a type is structured internally, so I neither have to accommodate that structure, nor can I do anything that would rely on that structure never being changed in the future.

Good example of me still having a lot to learn. If I've got any of this wrong, please help me out.

Campbell Ritchie
Marshal
Posts: 68857
275
It does specify that ints longs shorts and bytes are two's complement, chars are unsigned, and that floats and doubles are IEEE 754 numbers in 32 and 64 bits respectively, in the JLS, so they ought not to change ever.
We used to teach binary integer arithmetic (in 8 bits) and floating point arithmetic (IEEE 754 in 32 bits) to our freshers, so they should have some idea how the numbers are represented long before getting their BSc.

Campbell Ritchie
Marshal
Posts: 68857
275
• 1
You need to know about the structure of primitives so you know about overflow (integers) and underflow (floating‑point only). Actually floating‑point numbers can overflow too, in which case you get ±∞.

Stevens Miller
Bartender
Posts: 1464
32

Campbell Ritchie wrote:You need to know about the structure of primitives so you know about overflow (integers) and underflow (floating‑point only). Actually floating‑point numbers can overflow too, in which case you get ±∞.

That raises a very important pedagogical point: teaching someone to program before they know the limitations of the primitive types they will be working with is kind of like teaching someone how to build a house before they know how much weight a foundation can bear. Damien's problem should have been the actual subject matter of his assignment. Or, more precisely, he should have been given an assignment that would reveal to him, and help me learn to cope with, the limitations of floating-point numbers. (I suppose he might have been given such an assignment, and we just don't know about it, but that appears unlikely, to me.)

I never got a bachelor's in CS (mine's in physics). My master's program must have assumed we already knew this stuff, because it never came up directly. In my own case, I learned about two's-complement and various schemes for representing floats by reading Byte and working with a textbook the Sperry-Univac company used for an in-house course on computers. (My dad got that for me from a friend, when I was 15. I read the whole thing and they even let me take the final exam. I still have the certificate that says I passed, somewhere. The bums declined to give me a summer job, regardless, but I see that as their loss.)

But, yeah, this isn't something you can ignore if you're going to write computer programs. As dry as it may be to students hoping to write Xbox games, it really does need to be part of their primary education.

Piet Souris
Saloon Keeper
Posts: 3888
154
OP is having a minor problem with a boundary, and so he's facing some inaccuracy
that comes with floating points. That's all. Why OP should stop coding and follow a
course in IEEE 754: it seems a bit heavy to me.

Stevens Miller
Bartender
Posts: 1464
32
Piet, it's not "some innaccuracy" that is causing his problem. It's the fact that his code is written with the assumption that a computer using Java's type of floating-point numbers can add 0.1 and 0.1, and get 0.2, when it can't. That's a very, very common error for new programmers to make and, until they understand at least something about how digital computers store floating-point numbers, it can be virtually impossible to understand.

If he were computing points on a circle by entering an x and obtaining a y, the fact that floats/doubles are imprecise would, as you say, impose some inaccuracy upon his result. But his real problem is that he is trying to iterate a function over evenly space values in its range, and his approach is failing for a rather subtle reason. It doesn't matter that he's computing points on a circle (or even that he's computing anything based on his x value at all). What matters is that he wants his computer to generate a set of values (specifically, [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0, -0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1.0]), and that, although his code is arithmetically correct, it doesn't work. The reason it doesn't work has nothing to do with his math (which is fine). It doesn't work because Java literally cannot store the number 0.1 in a float (or a double). It stores a nearby value that, for many purposes, is good enough. But, when used to increment or decrement a loop-control variable, it's not that it isn't sufficiently accurate: it's that it doesn't work at all. (Put another way, he wants 21 values from his loop, and he's only getting 20, because floats and doubles can't do exact math. That's not an inaccuracy; it's a outright failure to meet his objective.)

(Oh actually, his program seems to work over the range [1, -1]. It breaks when he tries to cover the range [1.3, -1.3], so he is really trying to generate 27 values when he's only getting 26. Same point applies, though.)

Campbell Ritchie
Marshal
Posts: 68857
275
Are you still with us, Damien Sky

You have opened up an interesting discussion here. When I started programming Java® I was told never to use doubles or floats in loops because of such imprecision.

You can get tenths like this:-…but if you enter a negative number your loop will never start.

Have you thought of this formula for the y coordinates?
θ = r cos⁻¹x
y = r sinθ

There are methods in the Math class for sin() and cos⁻¹ (I think acos()).

Campbell Ritchie
Marshal
Posts: 68857
275
In my integer loop you would enter 13 for a radius of 1.3.

Piet Souris
Saloon Keeper
Posts: 3888
154

Stevens Miller wrote: (...)

The difference between you and me (in this respect) is that you consider this issue
far more fundamental than I do. And I respect your attempts to make the
inaccuracy that comes with floating points, clear to Damien. I can't give you a
cow for that, but accept my virtual one.

I only hope we didn't scare Damien off!

Greetz,
Piet

Winston Gutkowski
Bartender
Posts: 10777
71

Piet Souris wrote:OP is having a minor problem with a boundary, and so he's facing some inaccuracy
that comes with floating points. That's all. Why OP should stop coding and follow a
course in IEEE 754: it seems a bit heavy to me.

Popped back to this thread after a while. And I'm going to try and answer that (especially since I'm the one that wrote the StopCoding page ).

It's the same as the reason that I'm very grateful to have someone like you around when I make a mathematical fallacy. I'm NOT a mathematician, but I do at least know that it's possible for me to make dangerous assumptions based on what I think to be true. And I need a Piet to tell me when I'm wrong.

If Damien doesn't understand why floating-point values have these inbuilt "gotchas" (and I'm not sure that he needs to read the entire IEEE-754 spec; Goldberg explains it pretty succinctly) he runs the risk of simply learning this example by rote, and/or not recognising it when it comes up in other guises (eg, currency calculations).

StopCoding is along the same lines, except that it's procedural advice.

When you start out programming, the first thing you do is CODE; and if you're smart, you can actually get quite a way by simply coding, because you can store an entire algorithm in your head. But there comes a point at which that process breaks down - and if you've never learned any other way of doing things, it usually breaks down catastrophically.
It also manifests itself before then in an increasing frustration at "why things don't work". The poster feels that "it ought to be simple", but it isn't; and they find they're making basic mistakes. And the reason (at least in my opinion) is that they've only ever been used to dealing with a problem as a whole, and as problems increase in complexity they get overwhelmed by the scope - and hence they get early lessons in debugging and (even worse) "tweaking".

I think it's also sound psychology. How many times have you been told, when you're desperately trying to remember something that's just maddeningly out of reach:
Well, the same is true of logic. And stopping coding - especially if you remember the other part of that advice: turn your computer OFF - forces you into a different mindset. You can't code, so you're forced to think. Most pros I know spend very little time coding, and actually consider it the most boring part of their job, because all it involves is translating what they already know into Java (or whatever).

My TGIF 2¢-worth.

Winston

PS: Happy Halloween everybody.

Sheriff
Posts: 15504
263

Stevens Miller wrote:Winston's oft-given advice to stop coding (I tend to word that as, "keep your hands where I can see them and step away from the mouse")

Is it just a coincidence or is it a disturbing trend that more programmers do their work with a mouse these days? I for one still use a keyboard to program. In fact, I'm trying to free myself from having to use a mouse.

Winston Gutkowski
Bartender
Posts: 10777
71

Junilu Lacar wrote:In fact, I'm trying to free myself from having to use a mouse.

Get a copy of Solaris (if you still can) and turn the desktop off. Still the best Unix AFAIC - although I'm told that you can do similar things with Debian.

Winston

Damien Sky
Greenhorn
Posts: 14
1
My teacher has informed me that she worded her question wrong. It was only meant to be run for a radius of 1 with varying increments, not radii.

 Yeah, but is it art? What do you think tiny ad? Java file APIs (DOC, XLS, PDF, and many more) https://products.aspose.com/total/java