Why does this comparison give me 'false'? I looked at the source and Float.NaN is defined as
/**
* A constant holding a Not-a-Number (NaN) value of type
* <code>float</code>. It is equivalent to the value returned by
* <code>Float.intBitsToFloat(0x7fc00000)</code>.
*/
public static final float NaN = 0.0f / 0.0f;
EDIT: surprisingly, if I do this:
System.out.println("FC " + (Float.compare(Float.NaN, Float.NaN)));
it gives me 0. So Float.compare() does think that NaN is equal to itself!
Use Float.isNaN to check for NaN values.
Because Java implements the IEEE-754 floating point standard which guarantees that any comparison against NaN will return false (except != which returns true)
That means, you can't check in your usual ways whether a floating point number is NaN, so you could either reinterpret both numbers as ints and compare them or use the much cleverer solution:
def isNan(val):
return val != val
All I need to say is: Wikipedia About NaN.
It is written quite clearly. The interesting part is that the floating point NaN of the common standard expresses a NaN this way:
s111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
The s is the sign (negative or positive), the 1's are the exponent and the x is regarded as a payload.
Looking at the payload a NaN is not equal any NaN and there are rare chances that these information of the payload are interesting for you as a developer (e.g. complex numbers).
Another thing is that in the standard they have signalling and quite NaN. A signalling NaN (sNaN) means an NaN that should raises a reaction like a exception. It should be used to say out loud that you have a problem in your equation. A quiet NaN (qNaN) is a NaN that is silently passed on.
A sNaN that created a signal is converted to a qNaN to not further produce any more signals in subsequent operations. Remember some system define i^0 = 1 as a constant that NaN^0 = 1 holds true. So there are cases where people calculate with NaN.
So in the end I would go with this: qNaN != sNaN but this is internal and is not observable for the user (you cant check that). Mix along the payment and the sign (yes you can have negative and positive NaN) and it appears to me that always return NaN != NaN looks like a much wiser choice that I finally learned to appreciate -> I will never ever complain or wonder about the inequality of NaN again. Praise the folks who were that thoughtful giving us such a good standard!
By the way: Java uses a positive NaN with a payload of 0 (all x are zeros).
Related
This question already has an answer here:
Why is pow(-infinity, positive non-integer) +infinity?
(1 answer)
Closed 5 years ago.
I tried two different ways to find the square root in Java:
Math.sqrt(Double.NEGATIVE_INFINITY); // NaN
Math.pow(Double.NEGATIVE_INFINITY, 0.5); // Infinity
Why doesn't the second way return the expected answer which is NaN (same as with the first way)?
A NaN is returned (under IEEE 754) in order to continue a computation when a truly undefined (intermediate) result has been obtained. An infinity is returned in order to continue a computation after an overflow has occurred.
Thus the behaviour
Math.sqrt(Double.NEGATIVE_INFINITY); // NaN
is specified because it is known (easily and quickly) that an undefined value has been generated; based solely on the sign of the argument.
However evaluation of the expression
Math.pow(Double.NEGATIVE_INFINITY, 0.5); // Infinity
encounters both an overflow AND an invalid operation. However the invalid operation recognition is critically dependent on how accurate the determination of the second argument is. If the second argument is the result of a prior rounding operation, then it may not be exactly 0.5. Thus the less serious determination, recognition of an overflow, is returned in order to avoid critical dependence of the result on the accuracy of the second argument.
Additional details on some of the reasoning behind the IEEE 754 standard, including the reasoning behind returning flag values instead of generating exceptions, is available in
What Every Computer Scientist Should Know About Floating-Point Arithmetic (1991, David Goldberg),
which is Appendix D of
Sun Microsystems Numerical Computation Guide.
It is just acting as is described in the documentation of Math.
For Math.sqrt:
If the argument is NaN or less than zero, then the result is NaN.
For Math.pow:
If
the first argument is negative zero and the second argument is less than zero but not a finite odd integer, or
the first argument is negative infinity and the second argument is greater than zero but not a finite odd integer,
then the result is positive infinity.
As to why they made that design choice - you'll have to ask the authors of java.
Hi I have the following equation in a piece of java code:
double z = 0.002378 * (Math.pow((1 - (Math.pow(6.875, -6) * y)), 4.2561));
when I set y to be very large values, i.e 200000 I get Nan (Not a number) It's working okay at slightly lower values, 130000
Can anyone tell me why that is?
Additionally I've tried to port the above code from an original BASIC program:
.002378*(1-(6.875*10^-6*ALT))^4.2561
I may have done it wrong? The order of operations isn't very explicit in the BASIC code
Thanks
As the Javadoc for Math.pow explains:
If the first argument is finite and less than zero [… and] the second argument is finite and not an integer, then the result is NaN.
So whenever your y is great enough that 1 - (Math.pow(6.875, -6) * y is negative, you'll get NaN.
(This makes sense when you consider the underlying math. A negative number to a non-integer power is not a real number, and double has no way to represent complex numbers.)
Edited for updated question:
Your Basic code has 6.875*10^-6 (meaning 6.875 × 10−6), but your Java code has Math.pow(6.875, -6) (meaning 6.875−6), which is a somewhat greater value, so your Java code triggers this problem for somewhat smaller values of y. This may be why you're seeing this problem now. To match the Basic code, you should change Math.pow(6.875, -6) to 6.875e-6.
Raising a negative number to a non-integer power results in an imaginary number in complex number mathematics, a NaN in Java arithmetic. If you really need to do that calculation, you need a complex number package. However, it is more likely that there is an error in your equation or you are trying to use it outside its range of validity.
Negtive number with real number power may get NAN
Shouldn't the following statement hold?
assertTrue(Double.isNaN(Math.tan(Math.acos(0d))));
But instead of Double.NaN Java returns
6.123233995736766 * 10^-17
on my 64-bit box.
EDIT:
This was a Copy and Paste error. In fact Java returns 1.633123935319537E16
I'm aware that this is because of the floating point representation, but i was under the impression that those undefined values of the tangent function would get the same treatment as e.g. Math.sqrt(-1d) but I guess in this case java.lang.Math just checks if the argument is positive before evaluating.
I get something different.
System.out.println(Math.tan(Math.acos(0d)));
// and the tan for the next representable value.
System.out.println(Math.tan(Math.acos(0d) + Math.ulp(Math.acos(0d))));
prints
1.633123935319537E16
-6.218431163823738E15
A 64-bit floating point cannot represent PI/2 exactly (it has an infinite number of digits) it represents a number close to this value and the tan() of this value is finite.
double d=1/0.0;
System.out.println(d);
It prints Infinity , but if we will write double d=1/0; and print it we'll get this exception: Exception
in thread "main" java.lang.ArithmeticException: / by zero
at D.main(D.java:3) Why does Java know in one case that diving by zero is infinity but for the int 0 it is not defined?
In both cases d is double and in both cases the result is infinity.
Floating point data types have a special value reserved to represent infinity, integer values do not.
In your code 1/0 is an integer division that, of course, fails. However, 1/0.0 is a floating point division and so results in Infinity.
strictly speaking, 1.0/0.0 isn't infinity at all, it's undefined.
As David says in his answer, Floats have a way of expressing a number that is not in the range of the highest number it can represent and the lowest. These values are collectively known as "Not a number" or just NaNs. NaNs can also occur from calculations that really are infinite (such as limx -> 0 ln2 x), values that are finite but overflow the range floats can represent (like 10100100), as well as undefined values like 1/0.
Floating point numbers don't quite clearly distinguish among undefined values, overflow and infinity; what combination of bits results from that calculation depends. Since just printing "NaN" or "Not a Number" is a bit harder to understand for folks that don't know how floating point values are represented, that formatter just prints "Infinity" or sometimes "-Infinity" Since it provides the same level of information when you do know what FP NaN's are all about, and has some meaning when you don't.
Integers don't have anything comparable to floating point NaN's. Since there's no sensible value for an integer to take when you do 1/0, the only option left is to raise an exception.
The same code written in machine language can either invoke an interrupt, which is comparable to a Java exception, or set a condition register, which would be a global value to indicate that the last calculation was a divide by zero. which of those are available varies a bit by platform.
Upon checking Float.compare(f1,f2) I found that it compares f1f2
and returns -1,0,1.
Then it returns -1,0,1 if the values are -0.0, 0.0 or NAN.
What does that mean -0.0?
I would have expected something like
return (Math.abs(f1 - f2) - 0.001f) > 0)
where 0.001 is a given epsilon value.
Thanks.
-0.0 is the negative zero, as specified by the IEEE 754 standard.
If you're curious about how such a value might arise, the following article does a good job of explaining it: http://www.savrola.com/resources/negative_zero.html
As to not taking an epsilon value, this is how Float.compare is designed work (it's an exact comparison, not an approximate one). There's nothing to stop you from having another comparison function that does take an epsilon and does perform an approximate comparison.
Both exact and approximate comparisons of floating-point numbers have their uses.
As to your actual code, it suffers from a number of issues:
it isn't a three-way comparison like Float.compare;
it doesn't handle NaNs;
it is generally better to specify the epsilon as a relative value, not as an absolute one, so that it scales with f1 and f2 (see this article for a discussion).
My point here isn't to criticise your code but to show that writing good floating-point code is harder than it first looks.
Floating point arithmetic is tricky. This article throws some light on the basics.
-0 is signed zero:
In ordinary arithmetic, −0 = +0 = 0. However, in computing, some
number representations allow for the existence of two zeros, often
denoted by −0 (negative zero) and +0 (positive zero).
[...]
The IEEE 754 standard for floating point arithmetic (presently used by
most computers and programming languages that support floating point
numbers) requires both +0 and −0. The zeroes can be considered as a
variant of the extended real number line such that 1/−0 = −∞ and 1/+0
= +∞, division by zero is only undefined for ±0/±0 and ±∞/±∞.