Is there a good reason Math.floor() and Math.ceil() return double's instead of int (or more precisely long)? Is this just a matter of "it was done in JDK 1.0 this way and we can't change it" or is there some justification to it?
I haven't seen a better explanation other than "it's what the API documentation says", which doesn't really answer the question.
I think what Scott's trying to say is that Long.MAX_VALUE is 9223372036854775807 and (double) Long.MAX_VALUE is 9223372036854776000. Such large double precision numbers can't have a fractional part, so floor(...) or ceiling(...) does nothing.
There are no new questions, but there may be new answers.
I know what Scott is trying to say. But you missed what I was trying to say -- I can tell that because you used the phrase "fractional part". That's the decimal assumption again. Double values are binary, not decimal. I predict that you will find that
Besides being outside the range of significant digits, there's also a question of practical uses. In the vast majority of circumstances where I want to use floor/ceil, my numbers are well within long, even int ranges. It's hard for me to imagine a use where someone would want the floor/top of a number greater than the long limit, and even if they do these functions have no effect.
BTW, even if 10.0E100 / 7.0 is not an integer, the decimal value will be truncated in double since mantissa cannot express it, as demonstrated in the following code which outputs "true,true":
Note that if 10.0E10 is used as x, the output is "false,false", but then y and z are fully expressible within the limit of long.
I was looking through the Java source, and apparently values too large are ignored:
In short, the argument that ceil/floor return double 'because the input may be outside the range of long' is flawed because in actuality you should never call ceil/floor on those values anyway.
Also, there's a consistency argument to be made here, since Math.round() does return long/int. I still think they made a mistake with ceil/floor when they had it return double and I have yet to be persuaded otherwise.
That's true... there will be some point beyond which only integer values can be expressed by a double value. Presumably that's why the code you posted exists. So is that point higher than the maximum value for a long?
Well, I'm asking if there is a valid reason why it doesn't return an integer value and it doesn't seem like there is. It's a choice between making developers checking the size of their exponent (if they expect a value higher than the long range) versus making developers cast the output to int/long. Since the latter seems far more common to me in every day programming, I think the original Java developers made a mistake doing it this way. It should return a long value and throw an exception if over the long range, since it should not have been called on such a value in the first place.
Paul Clapham wrote:But you're basically saying "Well, in real life people aren't going to be using double values outside of the range of long anyway so it doesn't matter"... or am I straw-manning you?
No, I'm saying in real life you *should* never call ceil/floor on a value outside the long range since it has no effect. If that rule was followed, or alternatively if an exception was thrown if they did use such a large value, then the ceil/floor() could return long without issue.
Scott Selikoff wrote:No, I'm saying in real life you *should* never call ceil/floor on a value outside the long range since it has no effect.
So are you saying that I shouldn't be allowed to call ceil/floor on a value outside the long range? Because in real life I'm not going to surround all my calls to Math.floor by an if-statement which checks that I'm not going to do something which isn't allowed, even though that something is perfectly well-defined.
To me, calling ceil/floor on a double above the long range amounts to a programmer error. It's conceivable the call to check the number is outside the range is less expensive then the call to perform the truncation (since it includes the check implicitly), therefore its a wasted call.
I'm not saying everything should be surrounded by an if-statement, but if you are in a position where you need ceil/floor of a number, then's a good bet you know you are within long range already. BTW, I consider it a waste that developers have to cast return values from ceil/floor... I imagine the quantity of those casts far exceeds the number of times someone would need to implement the if statement.
I disagree. When you write code, you don't necessarily know what data people are going to put into that code. This isn't like having to check for null so you avoid NullPointerException, this would be like having to check for excessively big numbers. Just because you're only envisioning applications which use small numbers doesn't mean you should be forcing people with applications which do use large numbers to do workarounds so they can actually use them.
Likewise I disagree about "wasted calls"; the code you posted shows that isn't the case. And having to cast the double to long isn't a waste either; if the method had been declared to return a long, the cast would still be taking place, it would just be hidden inside the system code.
I guess we'll have to agree to disagree. I don't see the value in calling a method that returns the exact same value, of which the call could be avoided altogether. Having these functions return int/long would be a lot more useful as a developer. In short, both strategies do work, neither offers something the other does not. The difference is what kind of workload you want to put on the developer.
I agree that we'll have to disagree. For me the design error was having the round() method truncate the returned value down into the long range. We do agree that round() and floor() shouldn't be inconsistent in that way, we just disagree on how to fix it (in that alternate universe).