julia
julia copied to clipboard
Detailed description on floatmin and floatmax
It's intuitive to think that typemin will do the opposite of what typemax does - which it does:
help> typemin
typemin(T)
The lowest value representable by the given (real) numeric DataType T.
help?> typemax
typemax(T)
The highest value representable by the given (real) numeric DataType.
It's intuitive to think that Base.isless will do the opposite of what Base.isgreater does - which it does not (and the docs spelled it out):
help> isless
isless(x, y)
Test whether x is less than y, according to a fixed total order (defined
together with isequal).
help> Base.isgreater
isgreater(x, y)
Not the inverse of isless! Test whether x is greater than y, according to
a fixed total order compatible with min.
It intuitive to think that floatmin will do the opposite of what floatmax does - which it does not (and the docs didn't spelled it out):
help?> floatmin
floatmin(T = Float64)
Return the smallest positive normal number representable by the
floating-point type T.
help?> floatmax
floatmax(T = Float64)
Return the largest finite number representable by the floating-point type
T.
Both floatmin and floatmax return positive values, which isn't intuitive for anyone first using the function. So its best to spell this out, as have been done for other cases like Base.isless and Base.isgreater.
Moreover, since floatmin doesn't return the "smallest finite number representable by the floating-point type", a link in the see also section should be provided for users pointing to prevfloat, nextfloat, because:
julia> prevfloat(Inf)
1.7976931348623157e308
julia> nextfloat(-Inf)
-1.7976931348623157e308
helps return the largest and smallest finite number representable, which users can easily call other than the one provided for only largest finite numbers in floatmax.
I'm not a native speaker, but shouldn't it be "converse" rather than "inverse" in any case?
"converse" is great but then is it a "frequently-used" mathematical term?
"inverse" for anyone would mean the opposite or turn upside lol. But anyways, as I previously said, I was only following the isless and Base.isgreater format.
Anyone should get the wording right, but at least an info should be provided.
I was just thinking that in the context of functions, the inverse function is one that returns the argument to a given outcome of the original function. In this context, one might be led to think of a function like "which minimal floating point type do I need to represent a given number?" as the inverse function, so instead of Type -> Number have Number -> Type. Or maybe something related to "complementary", or, in fact, "negation"?
Actually, given that it seems so hard to precisely tell what these functions are not, perhaps we should remove those sentences and, if anything, demonstrate what we mean by an example below?
Demonstrating by example is great, but I think it should be an "add-on". I think its a bad way trying to tell what a function does from an example - the docs should do it.
Anyways, like I said earlier, its open to better wordings; but the fact that it should be removed all together would be devastating, because we humans assume a lot.
Anyone would assume isless and isgreater are opposite in concepts no matter how many examples you give. I think looking at it from your angle, maybe a !!! note should be provided instead, so the wordings can be placed there.
I would say the relevant meaning of "inverse" would be this, which is close but not quite right:
julia> inv(floatmax(Float32))
2.938736f-39
julia> floatmin(Float32)
1.1754944f-38
julia> nextfloat(0f0)
1.0f-45
If a negative explanation is needed, why not just state that typemin(T) will be ~~a large negative number~~ -Inf for any AbstractFloat type.
It seems the "inverse" is taking the main point from this PR.
The PR was initially opened to address the issue that the floatmin function should somehow indicate that it's not doing the opposite of floatmax, just like the Base.isgreater was stated as not necessarily doing the opposite of isless.
help?> Base.isgreater
isgreater(x, y)
Not the inverse of isless!
The word "inverse" was used as the same format was used on isless and Base.isgreater relationship. Maybe its not the best word, and "opposite" should be the best word I guess; but then we should change the word "inverse" to be "opposite" in Base.isgreater as well?
What do you think?
isgreater takes two arguments. I presume "inverse" there means you reverse them. That may not be an ideal word but it is clarified extensively just below. And is irrelevant to this PR.
PR was initially opened to address the issue that the floatmin function should somehow indicate that it's not doing the opposite of floatmax
But it is in some sense the opposite. Largest & smallest full-precision numbers. There are several other ways you could guess the wrong sense of "opposite" from the name, and get a less useful function. Picking one of these to make the very first sentence doesn't sound like the path to clarity.
julia> let T = Float32
x = floatmax(T)
@show eps(x)/x
y = floatmin(T)
@show eps(y)/y
eps(one(T))
end
eps(x) / x = 5.960465f-8
eps(y) / y = 1.1920929f-7 # all 3 same precision, to the precision of my demonstration
1.1920929f-7
julia> let T = Float32
x = nextfloat(zero(T))
@show eps(x)/x
end;
eps(x) / x = 1.0f0
@mcabbott your example above is very great, but you're an "insider". I think, for anyone not fully equipped with Julia, it assumes floatmin does the opposite of what floatmax does - I fell into this trap until I read the docs carefully.
floatmax does this:
Return the largest finite number representable by the floating-point type T.
So why would anyone not believe floatmin does this?
Return the smallest finite number representable by the floating-point type T.
But it doesn't and that's what I'm trying to address. Point a way in the docs to let the user know it's not; just as isless and Base.isgreater was.
To see my point, check out some of the examples for typemax:
help?> typemax
julia> typemax(Float64)
Inf
julia> floatmax(Float32) # largest finite floating point number
3.4028235f38
Why was floatmax introduced there with a meaningful comment? SIMPLE: to point users who didn't see what they were looking for with typemax to use floatmax. As for typemin, this isn't available. I've opened #46827 on that though.
But the point is clear:
- give users "little hint" on functions with possible "name collisions" e.g.
floatminandfloatmax, where the behaviour isn't what is intuitively expected; - functions with names where we intuitively expect it to return "some-kind-of" value based on its name, e.g
typemaxwould be expected to do whatfloatmaxdoes, but it doesn't based on special values, and the "little hint" was provided - which is great.
For what is worth, I've been using Julia for more than 6 years and I never came across the Base.isgreater function, which, as far as I can tell from https://docs.julialang.org/en/v1/search/?q=isgreater, isn't even part of the public API. So maybe that isn't the best example to look at.
"I never came come across it" you said. Do you think its great if we generalise your experience for everyone?
I use that A LOT, particularly for it behaviour with NaN and missing. I'm aware it's not part of the public API and its no issue.
Do you have another example to consider?
Return the smallest finite number representable by the floating-point type T.
But it doesn't
But it does! Here "smallest" means smallest in absolute value, large negative numbers are not small.
This is pretty standard, but again, mis-reading this as allowing large negative is one possible mis-reading, which the second paragraph can aim to warn you against, without assuming that you mis-read it exactly this way.
Moreover I changed the "largest" in floatmax to say "highest" so its consistent with typemax and typemin:
help?> typemin
typemin(T)
The lowest value representable by the given (real) numeric DataType T.
help?> typemax
search: typemax typemin
typemax(T)
The highest value representable by the given (real) numeric DataType T.