Velocity Reviews > Does C have function to get angle?

# Does C have function to get angle?

slebetman@yahoo.com
Guest
Posts: n/a

 11-24-2005
Dik T. Winter wrote:
> In article <(E-Mail Removed) .com> "William Hughes" <(E-Mail Removed)> writes:
> ...
> > 1. Behaviour dictated by the standard
> > 2. Behaviour on common hosted implementations
> > 3. Behaviour on non-hosted/embedded implementations
> > 4. Behaviour on my implementation (depressingly often
> > i386/Microsoft vcc)
> >
> > My initial statement was a mix of 1 and 2 (I am
> > not familiar with the systems in 3). The standard
> > allows .4999999999999999 to be converted to a floating
> > point value > 0.5, but this is very unlikely. On the
> > other hand it is likely that some systems may convert
> > 0.4999999999999999 to 0.5. (It is certain that some
> > systems will convert 0.49999999999999999 to 0.5)
> > The upshot is that is is likely that
> > floor(0.4999999999999999 +0.5) will equal 1 on some
> > systems (and certain that floor(0.49999999999999999 +0.5)
> > will equal 1 on some systems).

>
> But that is not really the problem, because in that case 0.4999...999 will
> compare equal to 0.5 (assuming a well-behaved floating-point system). On
> the other hand, it *is* possible that you have a number that compares
> smaller than 0.5 but where adding 0.5 to that number results in 1.0.
>
> The following program:
>
> #include <stdio.h>
> #include <stdlib.h>
>
> int main(void) {
> double d = 0.25, r;
> int i = 0;
> r = d;
> while(d < 0.5) {
> if(d + 0.5 == 1.0) {
> printf("equal at step %d\n", i);
> exit(0);
> }
> r = r / 2;
> i++;
> d += r;
> }
> }
>
> Will print
> equal at step 52
> on a Sun running Solaris, it will print
> equal at step 63
> on an Intel machine using gcc with -O3, and it will
> print nothing on that same machine using gcc without
> optimisation (but will termate). So under some circumstances
> we have a number that is smaller than 0.5 but where
> floor(x + 0.5) will yield 1.0.
>

Nicely illustrated. And it can be tested even on non "weird"
implementations

William Hughes
Guest
Posts: n/a

 11-24-2005

Dik T. Winter wrote:
> In article <(E-Mail Removed) .com> "William Hughes" <(E-Mail Removed)> writes:
> ...
> > 1. Behaviour dictated by the standard
> > 2. Behaviour on common hosted implementations
> > 3. Behaviour on non-hosted/embedded implementations
> > 4. Behaviour on my implementation (depressingly often
> > i386/Microsoft vcc)
> >
> > My initial statement was a mix of 1 and 2 (I am
> > not familiar with the systems in 3). The standard
> > allows .4999999999999999 to be converted to a floating
> > point value > 0.5, but this is very unlikely. On the
> > other hand it is likely that some systems may convert
> > 0.4999999999999999 to 0.5. (It is certain that some
> > systems will convert 0.49999999999999999 to 0.5)
> > The upshot is that is is likely that
> > floor(0.4999999999999999 +0.5) will equal 1 on some
> > systems (and certain that floor(0.49999999999999999 +0.5)
> > will equal 1 on some systems).

>
> But that is not really the problem, because in that case 0.4999...999 will
> compare equal to 0.5 (assuming a well-behaved floating-point system).

Well, if you expect

float(0.49999...9 + 0.5)

to equal 0 no matter how many 9's you have then it is a problem. But I
take your point. This is a simple consequence of finite precision
(inevitable on any real machine). x comparing less that 0.5 and
x+0.5 comparing greater than or equal to 1 is not. (not a simple
consequence in any case).

-William Hughes

On
> the other hand, it *is* possible that you have a number that compares
> smaller than 0.5 but where adding 0.5 to that number results in 1.0.
>
> The following program:
>
> #include <stdio.h>
> #include <stdlib.h>
>
> int main(void) {
> double d = 0.25, r;
> int i = 0;
> r = d;
> while(d < 0.5) {
> if(d + 0.5 == 1.0) {
> printf("equal at step %d\n", i);
> exit(0);
> }
> r = r / 2;
> i++;
> d += r;
> }
> }
>
> Will print
> equal at step 52
> on a Sun running Solaris, it will print
> equal at step 63
> on an Intel machine using gcc with -O3, and it will
> print nothing on that same machine using gcc without
> optimisation (but will termate). So under some circumstances
> we have a number that is smaller than 0.5 but where
> floor(x + 0.5) will yield 1.0.
> --
> dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
> home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

Michael Mair
Guest
Posts: n/a

 11-24-2005
Jordan Abel wrote:
> On 2005-11-24, http://www.velocityreviews.com/forums/(E-Mail Removed) <(E-Mail Removed)> wrote:
>
>>I haven't tried this but a float (not double) on a PIC C compiler (such
>>as HiTech C) might simply because it doesn't use the IEEE floating
>>point due to optimising for speed/space (hey, the PIC is a very small 8
>>bit machine).
>>Other than weird compilers not accurately implementing floats on 8 bit
>>machines there are also weird machines like the CDC and Cray which has
>>non IEEE conforming binary representation of floats. On these machines
>>the result may or may not be correct. Anyone have access to one of
>>these and print out their binary representation like Joe did?

>
>
> It's still hard to imagine a floating-point format in which 0.5 does not
> have an exact representation. Any system based on binary, it's
> 1*(2**-1), and even with a decimal [bcd] system it's 5*(10**-1).
>
> It's theoretically possible that a very bad system might get .49999... >
> .5 due to cumulative rounding error [say, .4+.09+.009+.0009+.00009...],
> but unlikely.

Yep, however, some popular DS9000 variants might have a FLT_RADIX which
is an odd prime number or a product of odd prime numbers.

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.

Dik T. Winter
Guest
Posts: n/a

 11-25-2005
Now for the round function. Here is a version that is (I think) fool-proof,
assuming a sane implementation:

double round(double x) {
if(fabs(x) < 0.5) { /* allow for bad behaviour when x close to +- 0.5 */
return 0;
} else if(x > 0) {
if(trunc(x) == x) { /* allow for rounding of integers to the next
return x;
} else {
return trunc(x + 0.5);
}
} else {
if(ceil(x) == x) { /* see above */
return x;
} else {
return ceil(x - 0.5);
}
}
}
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

William Hughes
Guest
Posts: n/a

 11-25-2005

Dik T. Winter wrote:
> Now for the round function. Here is a version that is (I think) fool-proof,
> assuming a sane implementation:
>
> double round(double x) {
> if(fabs(x) < 0.5) { /* allow for bad behaviour when x close to +- 0.5 */
> return 0;
> } else if(x > 0) {
> if(trunc(x) == x) { /* allow for rounding of integers to the next
> higher when adding 0.5 */
> return x;
> } else {
> return trunc(x + 0.5);
> }
> } else {
> if(ceil(x) == x) { /* see above */
> return x;
> } else {
> return ceil(x - 0.5);
> }
> }
> }

I am not sure what you are requiring of a sane implementation.

But it seems to me that even on a sane implementation we could
have

x compares less than 1.5

x + 0.5 compares equal to 2

Under the above would x not round to 2?

-if y is an integer, y+0.5 is exaclty representable and
the expression y+0.5 will produce this representation

(this could be considered sane behaviour for a system with
radix 2 assuming y is not too large)

Then we could have something like

double round(double x)
{
if(x < ((floor)(x) + 0.5) )
{
return floor(x);
}
else
{
return floor(x) +1;
}

}

-William Hughes

Dik T. Winter
Guest
Posts: n/a

 11-25-2005
In article <(E-Mail Removed) .com> "William Hughes" <(E-Mail Removed)> writes:
....
> I am not sure what you are requiring of a sane implementation.
>
> But it seems to me that even on a sane implementation we could
> have
> x compares less than 1.5
> x + 0.5 compares equal to 2

I think not. Consider 1.5, in binary that would be 1.1, and any number
larger than 1 and smaller than 1.5 would (in binary) start with 1.0.
Adding 0.5 to that would merely replace that 0 by an 1, and such a number
should not compare equal to 2. At least on a sane implementation. (I
have worked with only one system where two numbers could compare equal
while they actually were not equal, I tend to call such a system insane.)

> -if y is an integer, y+0.5 is exaclty representable and
> the expression y+0.5 will produce this representation
> (this could be considered sane behaviour for a system with
> radix 2 assuming y is not too large)

See the latter requirement. If y is too large this can be false.
Especially this is false under IEEE double precision when x is (say)
2^52 + 1. Adding 0.5 to it results in 2^52 + 2 (round to even rule).

> double round(double x)
> {
> if(x < ((floor)(x) + 0.5) )
> {
> return floor(x);
> }

I do not think you want this. Suppose x == 0.75, it will return 0.0.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

Gordon Burditt
Guest
Posts: n/a

 11-25-2005
> > I am not sure what you are requiring of a sane implementation.
> >
> > But it seems to me that even on a sane implementation we could
> > have
> > x compares less than 1.5
> > x + 0.5 compares equal to 2

>
>I think not. Consider 1.5, in binary that would be 1.1, and any number
>larger than 1 and smaller than 1.5 would (in binary) start with 1.0.
>Adding 0.5 to that would merely replace that 0 by an 1, and such a number
>should not compare equal to 2. At least on a sane implementation. (I

Consider this scenario:
x = 1.011111111111111111111111111111111111111111111111 111111 * 2^0
(This is math, not C, and ^ is the exponentiation operator).
but this is a result with excess precision kept in registers but
it can't be stored. The compiler has it in a register so it uses it
there, and it compares less than 1.5.

x + 0.5 = 1.111111111111111111111111111111111111111111111111 111111 * 2^0

Now C stores it in a double variable, which doesn't have so many
bits, so it gets rounded, to:
x + 0.5 = 1.0000000000000000000000000000000000000000000 * 2^1
and it will compare equal to 2.

(No quibbling over the number of bits shown being insufficient for
a double: this is just an example and I didn't want line wrap on
80 column screens.)

Now, I think keeping "excess precision" violates C99, but lots
of compilers do it anyway, and taking care to NOT do it can be a
significant performance hit on some architectures, so it may be
common to see this with real compilers (especially if they are
not invoked with the "strictly follow the excess-precision rules"
flag). But I don't think you get to call it an "insane" implementation
for allowing this.

Gordon L. Burditt

Dik T. Winter
Guest
Posts: n/a

 11-26-2005
In article <(E-Mail Removed)> (E-Mail Removed) (Gordon Burditt) writes:
> >I think not. Consider 1.5, in binary that would be 1.1, and any number
> >larger than 1 and smaller than 1.5 would (in binary) start with 1.0.
> >Adding 0.5 to that would merely replace that 0 by an 1, and such a number
> >should not compare equal to 2. At least on a sane implementation. (I

>
> Consider this scenario:
> x = 1.011111111111111111111111111111111111111111111111 111111 * 2^0
> (This is math, not C, and ^ is the exponentiation operator).
> but this is a result with excess precision kept in registers but
> it can't be stored.

Yes, I know everything about excess precision. Do you think it is sane
that the following program:
#include <stdio.h>
int equal(double x, y) {
return(x == y);
}
int main(void) {
double d, e;
.... perform some initialisations on d and e and continue with:
if(d != e && equal(d, e)) {
printf("Arghh\n");
}
}
prints something?

But whatever, a round function has only to do with its argument and if
everything is well, in the argument excess precision is properly removed.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

William Hughes
Guest
Posts: n/a

 11-28-2005

Dik T. Winter wrote:
> In article <(E-Mail Removed) .com> "William Hughes" <(E-Mail Removed)> writes:
> ...
> > I am not sure what you are requiring of a sane implementation.
> >
> > But it seems to me that even on a sane implementation we could
> > have
> > x compares less than 1.5
> > x + 0.5 compares equal to 2

>
> I think not. Consider 1.5, in binary that would be 1.1, and any number
> larger than 1 and smaller than 1.5 would (in binary) start with 1.0.
> Adding 0.5 to that would merely replace that 0 by an 1, and such a number
> should not compare equal to 2. At least on a sane implementation. (I
> have worked with only one system where two numbers could compare equal
> while they actually were not equal, I tend to call such a system insane.)

Well, flipping the bit may be best practice, but it is possible
(e.g. (as Gordeon Burrit pointed out) the use of an extended precision
register followed by rounding) to
get x + 0.5 equal to 2. It seems to me a bit strong
to call an implementation that does this insane.

>
> > How about assuming that
> > -if y is an integer, y+0.5 is exaclty representable and
> > the expression y+0.5 will produce this representation
> > (this could be considered sane behaviour for a system with
> > radix 2 assuming y is not too large)

>
> See the latter requirement. If y is too large this can be false.
> Especially this is false under IEEE double precision when x is (say)
> 2^52 + 1. Adding 0.5 to it results in 2^52 + 2 (round to even rule).

Indeed. However, if x is large enough for this to be an issue,
the utility of rounding x must be strongly questioned.

>
> > double round(double x)
> > {
> > if(x < ((floor)(x) + 0.5) )
> > {
> > return floor(x);
> > }

>
> I do not think you want this. Suppose x == 0.75, it will return 0.0.

I get ((floor)(0.75) + 0.5) = ( 0 + 0.5) = 0.5. What am I missing?

-William Hughes

Dik T. Winter
Guest
Posts: n/a

 11-29-2005
In article <(E-Mail Removed) .com> "William Hughes" <(E-Mail Removed)> writes:
> Dik T. Winter wrote:
> > In article <(E-Mail Removed) .com> "William Hughes" <(E-Mail Removed)> writes:
> > ...
> > > I am not sure what you are requiring of a sane implementation.
> > >
> > > But it seems to me that even on a sane implementation we could
> > > have
> > > x compares less than 1.5
> > > x + 0.5 compares equal to 2

> >
> > I think not. Consider 1.5, in binary that would be 1.1, and any number
> > larger than 1 and smaller than 1.5 would (in binary) start with 1.0.
> > Adding 0.5 to that would merely replace that 0 by an 1, and such a number
> > should not compare equal to 2. At least on a sane implementation. (I
> > have worked with only one system where two numbers could compare equal
> > while they actually were not equal, I tend to call such a system insane.)

>
>
> Well, flipping the bit may be best practice, but it is possible
> (e.g. (as Gordeon Burrit pointed out) the use of an extended precision
> register followed by rounding) to
> get x + 0.5 equal to 2. It seems to me a bit strong
> to call an implementation that does this insane.

We were talking about a function that does rounding. Such a function will
not receive excess precision numbers, except if it does not conform to the
standard.

> > > How about assuming that
> > > -if y is an integer, y+0.5 is exaclty representable and
> > > the expression y+0.5 will produce this representation
> > > (this could be considered sane behaviour for a system with
> > > radix 2 assuming y is not too large)

> >
> > See the latter requirement. If y is too large this can be false.
> > Especially this is false under IEEE double precision when x is (say)
> > 2^52 + 1. Adding 0.5 to it results in 2^52 + 2 (round to even rule).

>
> Indeed. However, if x is large enough for this to be an issue,
> the utility of rounding x must be strongly questioned.

Ah, you must also be questioning the utility of the IEEE standard trunc
and ceiling instructions. As a blackbox routine given a double precision
number, the routine should do whatever it can to return the best possible
result.

> > > {
> > > if(x < ((floor)(x) + 0.5) )
> > > {
> > > return floor(x);
> > > }

> >
> > I do not think you want this. Suppose x == 0.75, it will return 0.0.

>
> I get ((floor)(0.75) + 0.5) = ( 0 + 0.5) = 0.5. What am I missing?

My brain damage.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/