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.
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.
The documentation of the SE Math library is, thankfully, very transparent about rounding errors:
If a method always has an error less than 0.5 ulps, the method always returns the floating-point number nearest the exact result; such a method is correctly rounded. A correctly rounded method is generally the best a floating-point approximation can be; however, it is impractical for many floating-point methods to be correctly rounded. Instead, for the Math class, a larger error bound of 1 or 2 ulps is allowed for certain methods. Informally, with a 1 ulp error bound, when the exact result is a representable number, the exact result should be returned as the computed result; otherwise, either of the two floating-point values which bracket the exact result may be returned.
And every floating-point method mentions its error bounds in ulps. In particular, for Math.log():
Returns the natural logarithm (base e) of a double value...The computed result must be within 1 ulp of the exact result
Therefore, Math.log() will possibly round to the nearest representable value in the wrong direction.
I need a correctly rounded implementation of base-e log. Where might I find one?
I am writing tests for code performing calculations on floating point numbers. Quite expectedly, the results are rarely exact and I would like to set a tolerance between the calculated and expected result. I have verified that in practice, with double precision, the results are always correct after rounding of last two significant decimals, but usually after rounding the last decimal. I am aware of the format in which doubles and floats are stored, as well as the two main methods of rounding (precise via BigDecimal and faster via multiplication, math.round and division). As the mantissa is stored in binary however, is there a way to perform rounding using base 2 rather than 10?
Just clearing the last 3 bits almost always yields equal results, but if I could push it and instead 'add 2' to the mantissa if its second least significast bit is set, I could probably reach the limit of accuracy. This would be easy enough, expect I have no idea how to handle overflow (when all bits 52-1 are set).
A Java solution would be preferred, but I could probably port one for another language if I understood it.
EDIT:
As part of the problem was that my code was generic with regards to arithmetic (relying on scala.Numeric type class), what I did was an incorporation of rounding suggested in the answer into a new numeric type, which carried the calculated number (floating point in this case) and rounding error, essentially representing a range instead of a point. I then overrode equals so that two numbers are equal if their error ranges overlap (and they share arithmetic, i.e. the number type).
Yes, rounding off binary digits makes more sense than going through BigDecimal and can be implemented very efficiently if you are not worried about being within a small factor of Double.MAX_VALUE.
You can round a floating-point double value x with the following sequence in Java (untested):
double t = 9 * x; // beware: this overflows if x is too close to Double.MAX_VALUE
double y = x - t + t;
After this sequence, y should contain the rounded value. Adjust the distance between the two set bits in the constant 9 in order to adjust the number of bits that are rounded off. The value 3 rounds off one bit. The value 5 rounds off two bits. The value 17 rounds off four bits, and so on.
This sequence of instruction is attributed to Veltkamp and is typically used in “Dekker multiplication”. This page has some references.
Casting for integers is very straightforward, the extra bits simply disappear.
But, is it important to understand what is happening under the hood for casting floating point? I've tried to read information on how floating point is calculated, but I have yet to find one that explains it well. At least that's my excuse. I get the basic idea although the calculation of the mantissa is a bit difficult.
At least up to Java 7, I understand that floating points cannot be used in bitwise operations. Which makes sense because of how they are stored internally. Is there anything important that is needed to know on how floating points operate or are cast?
So, to Summarize:
Is it important to understand the internal workings of floating point like integers?
What is the internal process of casting a floating point to an integer?
What is the internal process of casting a floating point to an integer?
Java calls the machine code instruction which does this in compliance with the IEEE-754 standard. There is nothing for Java to do as such. If you want to know how casting works I suggest you read the standard.
Basically, the mantissa is shifted by the exponent and the sign applied. i.e. a floating point number is sign * 2^exponent * mantissa and all it does is perform this calculation and drop and fractional parts.
First, you need to understand that a floating point number is essentially an approximation. You can put in, say 1.23 and get out 1.229998 (or some such), because 1.23 is represented exactly. Regardless of whether you will be doing any casts, you need to understand this, and how it affects computations (and especially comparisons).
From the standpoint of cast, casting a float to a double causes no loss of information, since a double can contain every value that a float can contain. But casting from double to float can cause loss of precision (and, for very large or small numbers, exponent overflow/underflow), since there's simply more information in a 64-bit value than in a 32-bit one, so some data's going to end up "on the floor".
Similarly, casting from an int to a double causes no loss of information, since a double can contain every value an int can contain and then some. But casting from int to float or from long to double or float can result in loss of precision (though there can never be an exponent overflow/underflow).
Casting from float or double to int or long can easily result in overflow/underflow and major loss of data, if the float or double value has a large positive exponent or any negative exponent. And, of course, when you cast from floating-point to fixed the fractional part of the number is truncated (essentially a "floor" operation).
When I write something like
double a = 0.0;
double b = 0.0;
double c = a/b;
The result is Double.NaN, but when I try the same for integers, it produces an ArithmeticException. So, why isn't there a Integer.NaN?
The answer has very little to do with Java. Infinity or undefined numbers are not a part of the integer set, so they are excluded from Integer, whereas floating point types represent real numbers as well as complex numbers, so to deal with these, NaN has been included with floating point types.
For the same reason that there is no integer NaN in any other language.
Modern computers use 2's complement binary representation for integers, and that representation doesn't have a NaN value. (All values in the domain of the representation type represent definite integers.)
It follows that computer integer arithmetic hardware does not recognize any NaN representation.
In theory, someone could invent an alternative representation for integers that includes NaN (or INF, or some other exotic value). However, arithmetic using such a representation would not be supported by the hardware. While it would be possible to implement it in software, it would be prohibitively expensive1... and undesirable in other respects too to include this support in the Java language.
1 - It is of course relative, but I'd anticipate that a software implementation of NaNs would be (at least) an order of magnitude slower than hardware. If you actually, really, needed this, then that would be acceptable. But the vast majority of integer arithmetic codes don't need this. In most cases throwing an exception for "divide by zero" is just fine, and an order of magnitude slow down in all integer arithmetic operations is ... not acceptable.
By contrast:
the "unused" values in the representation space already exist
NaN and INF values are part of the IEE floating point standard, and
they are (typically) implemented by the native hardware implementation of floating point arithmetic
As noted in other comments, it's largely because NaN is a standard value for floating point numbers. You can read about the reasons NaN would be returned on Wikipedia here:
http://en.wikipedia.org/wiki/NaN
Notice that only one of these reasons exists for integer numbers (divide by zero). There is also both a positive and a negative infinity value for floating point numbers that integers don't have and is closely linked to NaN in the floating point specification.