Division by zero: float vs. int

M

Mark Thornton

Daniel said:
True. Strictfp only disallows using extended precision values for
intermediate calculations. Non-strictfp code allows intermediate
calculations in extended precision, but any assignments result in a
conversion back to the standard precision value sets. Even without
strictfp, the rules are quite strict, and are in conflict with the
choices made in e.g. the x87 fpu (I seem to recall that the java
floating point semantics are taken from some of Sun's fp implementations
in software. Not surprising, really.).

Even without strictfp, extended precision is not permitted. What is
allowed is an extended range for the exponent so that intermediate
extreme values may avoid overflow/underflow. This means for example that
you can't use fused multiply/accumulate instructions.

Mark Thornton
 
R

Razvan

Tor Iver Wilhelmsen said:
Because the floating point representation has bit patterns that are
set aside for the purpose. You cannot do the same for integers since

1) It would reduce the available value range.

2) You cannot reliably (except in Java, C# and the like) "know" how
large an integer is. If you declare 0xffffffff to be positive (or
negative?) infinity, you will run into trouble on machines with
larger representations of ints. Also, integers are often either
signed or unsigned - floating point is always signed.

Mmmmm... Such an algorithm can be implemented (sure why not ?!) but
its advantages will out weight the disadvantages – especially since
generation of programmers where educated in the C/C++ way of thinking.
As Stefan Schulz has noted, many algorithms will break and a new way
of thinking must replace the old one. This is a very slow process that
could slow down Java adoption.

Basically, 'trusted ways' and legacy algorithms are the reason for
this difference.
 
T

Thomas G. Marshall

Stefan Schulz coughed up:
The fact that it makes no sense logicwise. Is the natural Logarithm
of -2 the
same as the natural Logarithm of -5?

Yes IMO. And

sqrt(-10) ==should== sqrt(-20)

But it seems that I'm likely to be the minority here...
 
R

Razvan

Boudewijn Dijkstra said:
From a mathematical point of view, this is because integers are always exact
and floating point numbers are not. The idea is that you 'never' know what
was truncated to fit it in a finite number of bits.


I read your comment 5 times. I do not understand what you mean.
Both integers and floats have a finite number of bits.
 
L

Lasse Reichstein Nielsen

Thomas G. Marshall said:
Yes IMO. And

sqrt(-10) ==should== sqrt(-20)

But it seems that I'm likely to be the minority here...

It would be a bad idea to have an equality that didn't hold when you
extend the operation to complex/imaginary numbers. So count me
against :)

/L
 
T

Tor Iver Wilhelmsen

Dimitri Maziuk said:
E.g. you have to call ResultSet.wasNull() after ResultSet.getXXX(),
and ResultSet has to have an extra boolean flag to support that.

That has nada to do with integers supporting NaN. For instance, a
getString() can return "" and wasNull() return true, because the
implementation (say, Oracle) considers the empty string equivalent to
null. Having it return a constant String representing null instead of
using wasNull() is semantics (like your use of 0xffffffff for int),
but has the drawback that there's now one less String that can
reliably be put into a database.
E.g. array search has to return -n for "not found", which means you
can't have an array [-n..m]. A function that returns a signed
integer cannot return an error value, ever. Etfc.

Actual errors should be exceptions anyway. Or you couls argue for
adding by-reference parameters and using HRESULT equivalents.
The $15 question is whether the savings we get from having a simpler
adder outweigh the costs of extra complexity in the software.

Yes it does. :)

Now, if primitives were objects, you could have constant values for
"actual" nulls, but then you are letting database semantics dictate a
language that isn't SQL.
 
T

Tor Iver Wilhelmsen

Thomas G. Marshall said:
sqrt(-10) ==should== sqrt(-20)

No; For instance sqrt(-9) = 3i and sqrt(-100) = 10i; both are existing
(complex) numbers, they simply cannot be represented as reals.
 
S

Stefan Schulz

I read your comment 5 times. I do not understand what you mean.
Both integers and floats have a finite number of bits.

Any in-range Integer operation will alway yield the exact result.

However, look at the output of this little Program, and weep:

public class Numbers {

public static void main(String [] argv){
System.out.println(.1 * .1 == .01);
}
}
 
C

Chris Uppal

Tor said:
No; For instance sqrt(-9) = 3i and sqrt(-100) = 10i; both are existing
(complex) numbers, they simply cannot be represented as reals.

I say yes, i.e. I agree with Thomas.

The NaN result is saying "this calculation has no defined result", or -- if you
prefer to invoke the complex plane -- "this calculation has two values neither
of which can be approximated as floating point". I prefer the first
formulation, not least because we are /not/ working in the complex plane[*].

([*] Remember that the complex plane is not the only mathematical abstraction
that can be considered to embed the real line, and in which sqrt() is defined
for all real values)

So the NaN result is a meta-level assertion shoe-horned into IEEE FP
representation. It would obviously be better -- in general -- to throw an
exception (perhaps a resumable one), but IEEE doesn't have language-specific
concepts like that (AFAIK), so all it can do is represent the meta-linguistic
assertion as a special reserved bit pattern.

There are only a handfull of such meta-lingistic concepts needed to cover the
failure modes of fp calculations. I presume that IEEE have done their
homework, and have covered all the bases, and so that all the meaningfull
assertions of the form "this calculation has no result because..." have been
given NaN values or similar.

Now, I don't see any semantic utility in distinguishing between "sqrt(-1) has
no defined result" and "sqrt(-18) has no defined value" -- in fact I think they
are the /same/ assertion (especially since IEEE NaN does not preserve the
expression that could not be computed), i.e. I think that "this calculation has
no defined result" /should/ be treated as equal to "this calculation has no
defined result" -- indeed I'd say that it's /obvious/ that they should be
equal.

That isn't to say that I'd want to make all the different kinds of NaN equal.
And it may be that that is the motivation behind making none of them equal, not
even to themselves. Since Java has no clear concept of the different kinds of
NaN as first-class primitive values (e.g there are no float/double literals for
them).

Alternatively, it may be -- as a pragmatic matter -- that generations of
experience in "real" FP work by numerical programmers have found that the
semantically impure device of treating all NaNs as unequal results in simpler,
clearer, or faster expression of important caclulations, and that Java is just
following that. It sounds plausible to me, but I don't know (I'm /not/ a
numerical programmer -- I'm pleased to say ;-)

-- chris
 
M

Michael Saunby

[snip]
That isn't to say that I'd want to make all the different kinds of NaN
equal.
And it may be that that is the motivation behind making none of them
equal, not
even to themselves. Since Java has no clear concept of the different
kinds of
NaN as first-class primitive values (e.g there are no float/double
literals for
them).

I'd say that the rationale behind NaN not being equal to itself has less to
do with different types of NaN and just a simple desire to ensure that the
result of any floating point operation involving one or more NaN is also
NaN, and the logical extension of that to boolean operations is that they
should fail, when normally they would be true. i.e. if (a == a) should be
true for any value other than a NaN (including +/-inf) but false for NaN.
Alternatively, it may be -- as a pragmatic matter -- that generations of
experience in "real" FP work by numerical programmers have found that the
semantically impure device of treating all NaNs as unequal results in
simpler,
clearer, or faster expression of important caclulations, and that Java is
just
following that. It sounds plausible to me, but I don't know (I'm /not/ a
numerical programmer -- I'm pleased to say ;-)

In the Fortran implementations I've worked with it has been possible to
give a compilation flag to specify whether a program fails or continues on
encountering a NaN. This is a very blunt instrument though, in that the
program will abort not just on what most folks would consider a floating
point calculation yielding a NaN, but even reading one from a file.

Michael Saunby
 
C

Chris Uppal

Eric said:
The truly picky pedant may also wish to consider
Knuth's assertion (TAOCP vII, sec 4.1) that the way to
place the apostrophes is "two's complement" but "ones'
complement." I don't know whether his argument is
widely accepted, but it makes sense.

(That's on p203 of the second edition, for those who don't have time to read
the whole interesting chapter)

I don't think I'd want to take lessons in precise English from a guy who's
Quicksort implementation recurses into the larger subproblem and iterates into
the smaller...

;-)

-- chris

P.S. That's a genuine observation. Most odd. The error seems to be
duplicated in the "Numerical algorithms in C" book, too.
 
?

=?ISO-8859-1?Q?Daniel_Sj=F6blom?=

Mark said:
Even without strictfp, extended precision is not permitted. What is
allowed is an extended range for the exponent so that intermediate
extreme values may avoid overflow/underflow. This means for example that
you can't use fused multiply/accumulate instructions.

I'm glad you pointed this out. I was apparently wrong about the fp
semantics. So they are even stricter than I thought. I don't do much
floating point work myself though, so it does not really affect me.
 
T

Thomas G. Marshall

Chris Uppal coughed up:
(That's on p203 of the second edition, for those who don't have time
to read the whole interesting chapter)

I don't think I'd want to take lessons in precise English from a guy
who's Quicksort implementation recurses into the larger subproblem
and iterates into the smaller...

;-)

-- chris

P.S. That's a genuine observation. Most odd. The error seems to be
duplicated in the "Numerical algorithms in C" book, too.

At first read of this, ICBW, but isn't that how quicksort is supposed to
work? In the small, you lose far too much stack space and it just isn't
efficient enough to recur down to the individual members. No? {shrug}
 
T

Thomas G. Marshall

Michael Saunby coughed up:
message
[snip]
That isn't to say that I'd want to make all the different kinds of
NaN equal.
And it may be that that is the motivation behind making none of them
equal, not
even to themselves. Since Java has no clear concept of the different
kinds of
NaN as first-class primitive values (e.g there are no float/double
literals for
them).

I'd say that the rationale behind NaN not being equal to itself has
less to do with different types of NaN and just a simple desire to
ensure that the result of any floating point operation involving one
or more NaN is also NaN, and the logical extension of that to boolean
operations is that they should fail, when normally they would be
true. i.e. if (a == a) should be true for any value other than a
NaN (including +/-inf) but false for NaN.

Precisely why I feel otherwise.

I see your argument, but I'm still not sure that (NaN != NaN) is
particularly useful. You are still relegated to the common calls to
something of the form

isNaN(num) or
.isNan() for object versions

in all PL's that support the concept *anyway*. It makes sense to me to
allow the equality. After all, a whackjob number is a whackjob number :)

....[rip]...
 
T

Thomas G. Marshall

Stefan Schulz coughed up:
I read your comment 5 times. I do not understand what you
mean. Both integers and floats have a finite number of bits.

Any in-range Integer operation will alway yield the exact result.

However, look at the output of this little Program, and weep:

public class Numbers {

public static void main(String [] argv){
System.out.println(.1 * .1 == .01);
}
}

^H^H^H^H^H^H^Hgrammers. :)
 
D

Dimitri Maziuk

Tor Iver Wilhelmsen sez:
That has nada to do with integers supporting NaN. For instance, a
getString() can return "" and wasNull() return true, because the
implementation (say, Oracle) considers the empty string equivalent to
null.

Think again. getString() would return null *if* the standard said
so. The reason it doesn't is integers (and booleans, but those are
usually integers under the hood anyway) -- getInt() will always
return a valid integer because there ain't no such thing as
invalid one.
E.g. array search has to return -n for "not found", which means you
can't have an array [-n..m]. A function that returns a signed
integer cannot return an error value, ever. Etfc.

Actual errors should be exceptions anyway. Or you couls argue for
adding by-reference parameters and using HRESULT equivalents.

"Not found" is not an error. Exceptions exist so that compiler
(and programmer) can easily group error handling code into separate
chunks that don't even get loaded into memory 99% of the time.

When you have a "common" (as opposed to "exceptional") error
condition you usually don't want to use an exception to handle
it because of the overhead of swapping that chunk error-handling
code in and having to jump there from currently active page.
Now, if primitives were objects, you could have constant values for
"actual" nulls, but then you are letting database semantics dictate a
language that isn't SQL.

Huh? Null objects are actually null pointers: unsigned integers
pointing to memory address 0x00. Or 0xdeadbeef -- a perfectly
valid integer that represents a memory address that's either not
valid or is never ever available to the program.
(Just because Java is hiding that from you doesn't mean it isn't so.)

Where TF did you see database semantics here? I suggest you re-read
your Computer Organization 101 and Programming Languages 102 lecture
notes before discussing relative merits of different binary
representations in the future.

Dima
 
J

John C. Bollinger

Thomas said:
Michael Saunby coughed up:


Precisely why I feel otherwise.

I see your argument, but I'm still not sure that (NaN != NaN) is
particularly useful. You are still relegated to the common calls to
something of the form

isNaN(num) or
.isNan() for object versions

in all PL's that support the concept *anyway*. It makes sense to me to
allow the equality. After all, a whackjob number is a whackjob number :)

From a mathematical perspective, if I have two computations that both
produce undefined results, then it doesn't make sense to even ask the
question of whether those results are the same. If I do ask the
question, then it seems to me that "no" is a better answer than "yes":
if neither result is even defined then how can the two be the same? The
two results share the property of being undefined, but that's all you
can say about them. (It is probably even better to say that the
_computations_ share the property of having undefined results; you can't
compare the results themselves in any way because they don't exist.)

IEEE floating point provides a way to signal that a calculation has an
undefined result by means of special values of the algorithmic answer.
That's a lot better than fudging with a mathematically inconsistent
result or just plain failing, but a NaN result does answer a different
question than was posed to the numeric hardware. I agree that it would
be slightly more convenient to be able to use == to probe whether a
particular computation had a defined result, but that would produce its
own set of more difficult to catch anomalies in programs that compare
the results of different computations to each other.

From a practical perspective, I should also point out that although
Java specifies exactly one NaN value for double and one for float, IEEE
math provides for multiple bitwise distinct NaN values at both
precisions, so in general == must provide special cases for NaN values
no matter what.

I vote for the model that is more consistent with the mathematics (which
is the point of the model, after all) over the model that adds a minor
convenience for programmers.


John Bollinger
(e-mail address removed)
 
C

Chris Uppal

I suppose I should fill out what was really just intended to be a throwaway
irrelevant (and irreverent ;-) comment.

At first read of this, ICBW, but isn't that how quicksort is supposed to
work? In the small, you lose far too much stack space and it just isn't
efficient enough to recur down to the individual members.

There are two questions here.

It is indeed more efficient (in general) to stop quicksort before it gets down
to sorting the smallest sublists (switching to insert sort is the standard
approach), but that's not the issue I was talking about.

The questions is what do you do /before/ you've reached that point, when (at
each step of the algorithm) you have partitioned your input into two sublists.
You don't want to recurse into both, since that risks taking stack space that's
linear in the size of the input if you hit a pathological case. So what you do
is choose the /smallest/ sublist and recurse into that, while continuing your
(constant-space) iteration on the larger of the two sub-problems. That forces
the max stack depth to be at worst log2 N (since each recursive step must be
treating a sublist that is < 1/2 the size of the previous list).

Equivalently, you could say that you handle both sublists recursively, but you
make damn sure (hand coding it if necessary) that the recursive call to the
larger sublist is subject to tail-call optimisation.

I should say that Knuth's presentation[*] of the algorithm isn't explicitly
recursive (and neither is the one in "Numerical methods"). He uses iteration
plus an explicit stack (LIFO datastructure), rather than iteration plus the
system stack. But the error's the same in either case -- he is unecessarily
accepting a worst case O(N) tempory space consumption.

[*] This is from the second edition of Knuth Vol 3 and is taken from the text
presentation of the algorithm, not the MIX code -- I have no intention of
trying to read that!

(BTW, the reason, /I/ know about this is not because I have gone over Knuth's
work with a fine-tooth comb (I didn't even have a copy until fairly recently).
But one of my programs (not in Java) unexpectedly blew up in my face when I was
sorting some list, and when I investigated I discovered that the implementation
was broken in this way. The authors of that sort routine pointed the finger at
"Numerical methods in C" as the source of the mistake (where, incidently, the
code even includes a comment "Push pointers to larger subarray on stack,
process smaller subarray immediately", so it's not a typo). "Numerical
methods" in turn states that the implementation "closely follows [Knuth]")

-- chris
 
T

Thomas G. Marshall

Chris Uppal coughed up:
Thomas G. Marshall wrote:

I'd feel better if there was a "ME:" in front of the ">>" reply block so it
doesn't read "Thomas G. Marshall wrote: >> /quote/", even though the ">>" is
understood to be someone else, and you point it out that it was you.

I suppose I should fill out what was really just intended to be a
throwaway irrelevant (and irreverent ;-) comment.

Your post was clear. Thanks for the clarification.


....[rip]...



--
Iamamanofconstantsorrow,I'veseentroubleallmydays.Ibidfarewelltoold
Kentucky,TheplacewhereIwasbornandraised.ForsixlongyearsI'vebeenin
trouble,NopleasureshereonearthIfound.ForinthisworldI'mboundtoramble,
Ihavenofriendstohelpmenow....MaybeyourfriendsthinkI'mjustastrangerMyface,
you'llneverseenomore.ButthereisonepromisethatisgivenI'llmeetyouonGod's
goldenshore.
 
T

Thomas G. Marshall

John C. Bollinger coughed up:
From a mathematical perspective, if I have two computations that both
produce undefined results, then it doesn't make sense to even ask the
question of whether those results are the same. If I do ask the
question, then it seems to me that "no" is a better answer than "yes":
if neither result is even defined then how can the two be the same?
The two results share the property of being undefined, but that's all
you can say about them. (It is probably even better to say that the
_computations_ share the property of having undefined results; you
can't compare the results themselves in any way because they don't
exist.)

IEEE floating point provides a way to signal that a calculation has an
undefined result by means of special values of the algorithmic answer.
That's a lot better than fudging with a mathematically inconsistent
result or just plain failing, but a NaN result does answer a different
question than was posed to the numeric hardware. I agree that it
would be slightly more convenient to be able to use == to probe
whether a particular computation had a defined result, but that would
produce its own set of more difficult to catch anomalies in programs
that compare the results of different computations to each other.

From a practical perspective, I should also point out that although
Java specifies exactly one NaN value for double and one for float,
IEEE math provides for multiple bitwise distinct NaN values at both
precisions, so in general == must provide special cases for NaN
values no matter what.

I vote for the model that is more consistent with the mathematics
(which is the point of the model, after all) over the model that adds
a minor convenience for programmers.


I disagree, but I understand this point.

Perhaps consider this code:

double pi_1 = computePIoneWay();
double pi_2 = computePIanotherWay();
if (pi_1 == p1_2)
{
//we know mechanisms are the same...
}

vs.

double pi_1 = computePIoneWay();
double pi_2 = computePIanotherWay();
if ((pi_1 == p1_2) ||
(isNaN(pi_1) && isNaN(pi_2)))
{
//we know mechanisms are the same...
}

{shrug}


--
Iamamanofconstantsorrow,I'veseentroubleallmydays.Ibidfarewelltoold
Kentucky,TheplacewhereIwasbornandraised.ForsixlongyearsI'vebeenin
trouble,NopleasureshereonearthIfound.ForinthisworldI'mboundtoramble,
Ihavenofriendstohelpmenow....MaybeyourfriendsthinkI'mjustastrangerMyface,
you'llneverseenomore.ButthereisonepromisethatisgivenI'llmeetyouonGod's
goldenshore.
 

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,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top