Hi,
a very unpleasant behaviour which I believe is a bug is: if I add a float to an integer range, the result may have a different length due to roundoff error. The range gets converted to float range, which I think is a fault, since while valid in some idealized math, it shall never be regarded equivalent in floating point.
Example:
aa = (0.5 .+ 0:3)*pi/2
ab = (0.5 .+ collect(0:3))*pi/2
@show length(collect(aa)) length(collect(ab))
No. The sequence of operations is to blame here. It seems .+
has higher priority than :
.
@tomaklutfu: I am highly unsure if the precedence of operators is the key to success. In both ways the result is a range defined by floats, 0.5:1:2.5 and 0.5:1:3.5. I am convinced both ways are wrong -- it is never OK to rely on the fact the <=
condition will be met at the end bound. So I insist the behavious is wrong regardless on the operator precedence.
@yuyichao: Why do you close the issue (which has not been resolved anyhow) without giving any comment?
Try aa = (0.5 .+ (0:3))*pi/2
. What you wrote is equivalent to aa = ((0.5 .+ 0):3)*pi/2
.
@simeonschaub: In understand what you write, which is the same what @tomaklutfu said. But still the behaviour is wrong, because having a floating-point defined range whose length depends on round-off may not necessarily give the correct result.
@hrobotron I only talked about the example. I think you have to show a problematic case though. Also, it will be a problem around 2^52 which is a lot.
A lot of thought has actually gone into implementing floating point ranges in Base, so that this kind of roundoff error doesn't happen. Have a look at the docstring for StepRangeLen
: https://docs.julialang.org/en/v1/base/math/#Base.StepRangeLen
@tomaklutfu: I understand your point, and I thank you for the explanation of how operator precedence spoiled the result.
I anyway maintain that the deliberate conversion of integer range to float range is hazardous, however to fabricate the example of failure is maybe not that easy.
@simeonschaub: thank you for the reading, I will have a look.
"In conjunction with TwicePrecision this can be used to implement ranges that are free of roundoff error." OK then, thank you all for your time.
Actually, the resulting range has the length preserved.
julia> collect(((2^62-1):(2^62+1)) .+ floatmin())
3-element Vector{Float64}:
4.611686018427388e18
4.611686018427388e18
4.611686018427388e18
Most helpful comment
No. The sequence of operations is to blame here. It seems
.+
has higher priority than:
.