Does C have function to get angle?

S

slebetman

Dik said:
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 ;-)
 
W

William Hughes

Dik said:
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
 
M

Michael Mair

Jordan said:
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
 
D

Dik T. Winter

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);
}
}
}
 
W

William Hughes

Dik said:
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?

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)


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
 
D

Dik T. Winter

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

Gordon Burditt

I am not sure what you are requiring of a sane implementation.
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.011111111111111111111111111111111111111111111111111111 * 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.111111111111111111111111111111111111111111111111111111 * 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
 
D

Dik T. Winter

>
> Consider this scenario:
> x = 1.011111111111111111111111111111111111111111111111111111 * 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.
 
W

William Hughes

Dik said:
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.
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.
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
 
D

Dik T. Winter

>
>
> 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.
>
> 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.
>
> I get ((floor)(0.75) + 0.5) = ( 0 + 0.5) = 0.5. What am I missing?

My brain damage.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,832
Latest member
GlennSmall

Latest Threads

Top