Float comparison

C

CBFalconer

Flash said:
I was trying to get a concrete example that we could talk about. For
example the ranges could be 0.9<=valone<1.1 and 1.1<=valoneandabit<1.2
Obviosuly those would not be valid for a C implementaion, and the
decimal numbers specified are mathematical real numbers, as are the
comparison operators mathematical operators.


No it is not. In fact, that is not even related to the question.

It certainly is. Look at the code you posted. It is still above.
I want specific numerical values. If the bounds you specify are not
included that is important.

They depend on DBL_EPSILON. Look in your float.h file, or emit it
from a program. I don't know what it is for you.
No it isn't. It will be the range of the next representable number
above 1.0 in the direction of 100. I.e. a range only a very small
amouont larger than 1.0

Not a chance. 100 is much larger that 1. I don't know where you
got that description of valueandabit.
Which when you get the correct values will be in important point, so
think carefully.


I want the values for a REAL implementation, one you have to hand by
preference. Not symbols, but actual real numbers. I accept that other
implementations will be different, but I believe I can prove some of
my points on one specific implementation of *your* choice.

So don't say 1.0+DBL_EPSILON etc, do the calculation and give the
exact number.

Can't. I don't know what DBL_EPSILON is on your machine. Even if
I did know, it doesn't apply to my machine. You are being
completely unreasonable.
 
C

CBFalconer

Ben said:
.... snip ...


There are a number of possible values for this xmax. Do you intend
that these ranges overlap and if so by how much?

No, there are not. xmax is the smallest number we can hand to this
fp-system and have it store it as y, where y == nextafter(x, x+1);
If they are not intended to overlap then you can define xmax as the
smallest real that "converts" to a float > x and ymin to be the
largest that converts to x (x and y being consecutive floats). It
looks like ymin < xmax always but because the reals are closed under
taking limits, this definition will (for most real FP systems) result
in ymin == xmax.

Only if you ignore the multiplication by x or y. Since x < y then
x*(1+EPS) is not equal to y*(1-EPS). Those operations are
performed on the fp-system, so we know that 1+EPS is not 1.0, etc.
We are feeding the system actual real values, and taking what it
gives back.
I.e. there will always be a larger ymin and a
smaller xmax until, in the limit, a unique real, b == xmax == ymin,
defines the boundary between the ranges of x and y. I suspect this is
not what you mean because you were adamant that ymin < xmax.

No, you have omitted the step of passing the value to the fp-system
to store and looking at what it actually stored.
It would help me if you would clear this up. Did you really mean that
I can pick *any* real that converts to y as xmax or did you mean that
xmax is smallest such real? Of course, you might have intended a
third, as yet unspecified, way to pick xmax.

xmax is the smallest such real THAT CAN BE expressed in the
fp-system. We can't avoid this leaping from real to fp-system and
back. At least I don't see how.
 
F

Flash Gordon

Keith said:
CBFalconer said:
Flash Gordon wrote: [...]
OK, if that is all you can cope with, then I will ask my question given
EXPLICIT EXACT VALUES. First I need values you will accept. So..

Here are two lines of C code.

int main(void)
{
double valone = 1.0;
double valoneandabit = (valone, 100.0);
/* rest of program irrelevant to discussion */
return 0;
}

Now, I know you have access to a C compiler. If on YOUR SPECIFIC
compiler you were to compile and run the above, what are the EXACT
numerical ranges for valone and valoneandabit. I.e. I am asking for a
concrete numerical answer.
I don't know what you are getting at. The answer is 100.0.

There was an error in Flash's code. Rather than

double valoneandabit = (valone, 100.0);

he meant to write:

double valoneandabit = nextafter(valone, 100.0);

Yes, and this correction (and my acknowledgement of it) had already been
posted here.

So, Chuck, please tell me the exact numerical ranges of the two
variables in an implementation of your choice here:

#include <math.h>
int main(void)
{
double valone = 1.0;
double valoneandabit = nextafter(valone, 100.0);
/* rest of program irrelevant to discussion */
return 0;
}

I explicitly want numbers for a reason. I know the numbers will be
different on other implementations, but that does not matter for what I
want to show you.
 
C

CBFalconer

Dik T. Winter said:
This does *not* tell you that floats are not closed. Floats are
closed. If I take two floats (a and b), the operand + and calculate
a + b, the result is a float. That means the operation is closed.

What you are writing above is that they do not form a group, but
that is something completely different.

I am quite prepared to concede the point. My math was learned 60
years ago, and I have forgotten most of it. :)
 
C

CBFalconer

Keith said:
.... snip ...


The division is performed on operands of type double, and yields a
result of type double. It cannot yield the real value 1/3.

Let's expand it a bit:

double divide(double num, double den) {
double result = num / den;
return result;
}

...

double x = divide(1.0, 3.0);

This shouldn't make any difference, but it should make it clearer that
the value assigned to x is a double value.

So what? The system had the information to create 1/3. It
couldn't. So it created the nearest possible approximation IN THAT
fp-system. Somewhere between the call to divide, and the return
from divide, it did the approximation. The result may well be
different on a different system. The input data will not be
different.

You can change the word 'double' to 'float' or to 'long double'
everywhere within the function definition and the declaration of
x. You will get different results for each. However, the input
data will be the same. I.e. the value to be stored doesn't change,
but the value actually stored does.

(Barring systems that can't express 1.0 and 3.0 exactly)
 
C

CBFalconer

Richard said:
.... snip ...


No, it didn't. The system never even attempted to _compute_ the
real number one-third, let alone store it anywhere.

Certainly it did. It handed the integers 1 and 3 to a divide
routine. The divide routine labored mightily, but failed to
complete the division, so it returned the nearest value it could
calculate.
 
C

CBFalconer

Dik T. Winter said:
Wrong. It is not the storing that changed it from 1.0/3.0 to
whatever was stored, it was the calculation that made the change.
Or do you assert that (1.0 / 3.0) * 3.0 == 1.0 should always be
true (as nothing is stored ever)?

Are you claiming that, in your expression, (1.0 / 3.0) is never
stored anywhere, including in registers?
 
C

CBFalconer

Keith said:
.... snip ...

Upthread, you wrote:
| EPSILON defines the minimum increment to x which requires a
| different fp-object value. I.e. any smaller increment to x will
| be ignored by the hardware. If it is used as "-EPSILON" it MAY
| be a different value, however that only happens when x is a power
| of 2 in most implementations. C specifies it when x is 1.0.

I took that to mean that EPSILON is the difference between x and
the next number after x. I suppose you meant that EPSILON is
used in the formula to compute that difference, not that EPSILON
is that difference.

All we are told about EPSILON is:

-- the difference between 1 and the least value greater
than 1 that is representable in the given floating
point type, b1-p

which is enough. The further extensions are based on knowledge of
how typical fp-systems are implemented. Luckily most fp-systems
are similar.
 
C

CBFalconer

Dik T. Winter said:
Note that your EPSILON is *not* equal to nextafterf(x, 2.0) - x,
even when x in the range (1.0, 2.0). In many cases (exactly one
half of the cases (nextafter(x, 2.0) - x)/2.0 is the minimum
increment to x which gives a different fp_object, and is not
ignored by the hardware.

I don't believe I ever claimed it was equal. Just that they are
related.
 
C

CBFalconer

Dik T. Winter said:
You should ask IEEE for that, it is part of the IEEE standard.
But I think it is because it is a convenient way to use a
single instruction to find the next number in the direction of
infinity, in the direction of -infinity and in the direction of
0. All three can be useful at times.

I doubt that the average library has thoroughly tested nextafter(),
and would expect bugs to be likely to show up with second arguments
of +INF, 0, -INF. Especially the INFs.
 
K

Keith Thompson

CBFalconer said:
For the value 1/3 you can pass the integers 1 and 3 to a fp
division routine, and store whatever appears.

float storeratio(int num, int denom) {
return (float)num / denom;
}

You don't really need the function, but it clears up what is being
done. The fp-system received two integers, and converted them into
a representation of their ratio. Is there any argument about the
value of the ratio of 1 to 3?

Of course there's an argument about it; that's what this entire thread
has been about!

If I call storeratio(1, 3), I don't get the real value one-third. I
get a value of type float, a value that corresponds to a real number
close to the real number one-third. Your function performs a
floating-point division, not a mathematical real division.

Look at it this way. There are multiple different "/" operators for
different sets and/or types.

In the mathematical real numbers, 1/3 yields exactly one-third (this is
perhaps the kind of division on which the others are based).

In the mathematical integers, which are a subset of the reals, the
real value one-third can't be represented, so 1/3 yields 0.

In the C type int, which is a subset of the integers, which in turn is
a subset of the reals, 1/3 again yields 0.

In the floats, again, the real value one-third can't be represented,
so 1.0/3.0 yields a float value that's close to one-third, typically
something like 0.3333333432674407958984375.
 
K

Keith Thompson

CBFalconer said:
Now you are bringing in the programming. Certainly you CAN do
such. I am talking about what you can deduce from the fp-object
alone.

You keep saying "object" when you mean "value".
 
K

Keith Thompson

CBFalconer said:
So what? The system had the information to create 1/3. It
couldn't. So it created the nearest possible approximation IN THAT
fp-system. Somewhere between the call to divide, and the return
from divide, it did the approximation. The result may well be
different on a different system. The input data will not be
different.

So the mathematical value 1/3 never exists in the program, only a
floating-point approximation to it.

And I can tell you exactly where the approximation occurs: it's in the
evaluation of the "/" operator. The "/" operator takes two double
operands, with values 1.0 and 3.0, and it yields a double
approximation to one-third.
You can change the word 'double' to 'float' or to 'long double'
everywhere within the function definition and the declaration of
x. You will get different results for each. However, the input
data will be the same. I.e. the value to be stored doesn't change,
but the value actually stored does.

And here you're making a false distinction between "the value to be
stored" and "the value actually stored". There is no such
distinction. The value to be stored *is* the value actually stored,
and it's the value yielded by the "/" operator. And that value is an
approximation to one-third. The real value one-third does not exist
in the program, and cannot even be expressed in C (at least not in
this kind of context; of course you can build a rational number
package, but that's irrelevant to the point).
 
F

Flash Gordon

CBFalconer said:
You aren't considering actuality. You don't have an 'exact
answer'. You have an fp-value, which can represent any real in the
'range' for that value. That 'range' may be tight enough so that
you can ignore it, but if not you have to consider it.

For the third time, please READ the paper. Don't ASSUME you know what it
is talking about until AFTER you have read it.

As you said (incorrectly) about me, you are not paying attention.
 
K

Keith Thompson

CBFalconer said:
Certainly it did. It handed the integers 1 and 3 to a divide
routine. The divide routine labored mightily, but failed to
complete the division, so it returned the nearest value it could
calculate.

No it did not. It did not "labor mightily" and fail in its task. It
did exactly what it was written to do: compute and return a
floating-point approximation to one-third.

*That's what division means for floating-point types.*
 
K

Keith Thompson

CBFalconer said:
All we are told about EPSILON is:

-- the difference between 1 and the least value greater
than 1 that is representable in the given floating
point type, b1-p

which is enough. The further extensions are based on knowledge of
how typical fp-systems are implemented. Luckily most fp-systems
are similar.

That completely fails to address what I wrote.

One more time:

When you wrote "EPSILON defines the minimum increment to x ...", I
took that to mean that "EPSILON *is* the minimum increment to x".
After going back and forth a number of times, I think what you
actually meant is that the minimum increment to x *can be computed*
from EPSILON.

Do I now correctly understand what you mean by EPSILON? (And do you
see how your original statement could have been misleading?)
 
K

Keith Thompson

CBFalconer said:
I doubt that the average library has thoroughly tested nextafter(),
and would expect bugs to be likely to show up with second arguments
of +INF, 0, -INF. Especially the INFs.

Really? Why don't you try it and get back to us. I'd be astonished
if a released library had bugs like the ones you say you expect.
 
K

Keith Thompson

CBFalconer said:
It certainly is. Look at the code you posted. It is still above.

Perhaps in a week or so you'll get around to reading the articles that
correct the error in Flash's code. The line
double valoneandabit = (valone, 100.0);
was meant to be
double valoneandabit = nextafter(valone, 100.0);

[...]
Can't. I don't know what DBL_EPSILON is on your machine. Even if
I did know, it doesn't apply to my machine. You are being
completely unreasonable.

He's asking you to do the calculation *for your implementation*.
 
F

Flash Gordon

CBFalconer said:
It certainly is. Look at the code you posted. It is still above.

Yes, and had you been paying attention you would have seen the
correction posted by Kieth which I acknowledged. It was meant to call
nextafter.
They depend on DBL_EPSILON. Look in your float.h file, or emit it
from a program. I don't know what it is for you.

I specified YOUR implementations. You have access to the implementation
on your computer, I assume, so you can find out what values it uses.
Not a chance. 100 is much larger that 1. I don't know where you
got that description of valueandabit.

See the correction that had been posted twice before your first
question. It was meant to have a call to nextafter.
Can't. I don't know what DBL_EPSILON is on your machine. Even if
I did know, it doesn't apply to my machine. You are being
completely unreasonable.

I asked about your machine, not my machine. I SPECIFICALLY asked about
yours because you have access to it.

Here is the corrected program...

#include <math.h>
int main(void)
{
double valone = 1.0;
double valoneandabit = nextafter(valone, 100.0);
/* rest of program irrelevant to discussion */
return 0;
}

Now please tell me on YOUR computer, on YOUR C implementation, the EXACT
numeric ranges. You can't claim you don't have the information for this,
since I'm not asking you to look at anything other that your own
implementation.
 
F

Flash Gordon

CBFalconer said:
Certainly it did. It handed the integers 1 and 3 to a divide
routine. The divide routine labored mightily, but failed to
complete the division, so it returned the nearest value it could
calculate.

No, it used an algorithm designed to compute a value close to one third.
 

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

No members online now.

Forum statistics

Threads
474,434
Messages
2,571,685
Members
48,796
Latest member
Greg L.

Latest Threads

Top