Skip to content

Conversation

@adienes
Copy link
Member

@adienes adienes commented Sep 26, 2025

fixes #59661

@adienes adienes added maths Mathematical functions bugfix This change fixes an existing bug labels Sep 26, 2025
@adienes adienes added backport 1.10 Change should be backported to the 1.10 release backport 1.12 Change should be backported to release-1.12 labels Sep 26, 2025
@adienes
Copy link
Member Author

adienes commented Sep 26, 2025

I think the docs could stand an update, as applying a function -n times doesn't make much sense (although ofc most people will likely understand what it's intending to say)

instead of

nextfloat(x::AbstractFloat, n::Integer)
The result of n iterative applications of nextfloat to x if n >= 0, or -n applications of prevfloat if n < 0.

it should probably be something more like

The result of n iterative applications of nextfloat to x if n >= 0, or if n < 0, return a value p such that prevfloat(p, n) == x

but I don't want to change the docs in this PR as that would likely invite stricter scrutiny

@nsajko
Copy link
Member

nsajko commented Sep 27, 2025

This change could break prevfloat for a package which implements nextfloat and expects prevfloat to have a generic fall back implemented using nextfloat. So I think this may be a "minor change"?

@nsajko
Copy link
Member

nsajko commented Sep 27, 2025

I guess you may want to use the new ispositive and isnegative, instead of <.

@adienes
Copy link
Member Author

adienes commented Sep 27, 2025

This change could break prevfloat for a package which implements nextfloat and expects prevfloat to have a generic fall back implemented using nextfloat

those packages were already broken as the existing fallback is incorrect

@KristofferC KristofferC mentioned this pull request Sep 30, 2025
47 tasks
@vtjnash vtjnash requested a review from oscardssmith October 3, 2025 20:05
Copy link
Member

@vtjnash vtjnash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@adienes adienes merged commit 3b1fa7c into JuliaLang:master Oct 5, 2025
5 of 7 checks passed
@adienes adienes deleted the prevfloat_unsigned branch October 5, 2025 11:42
KristofferC pushed a commit that referenced this pull request Oct 6, 2025
@adienes adienes removed the backport 1.10 Change should be backported to the 1.10 release label Oct 10, 2025
KristofferC pushed a commit that referenced this pull request Oct 12, 2025
@KristofferC
Copy link
Member

This caused e.g. the following package to error:

Machine precision: Error During Test at /home/pkgeval/.julia/packages/Measurements/pivk0/test/runtests.jl:723
  Test threw exception
  Expression: ≈(prevfloat(y, 3), prevfloat(y.val, 3) ± y.err, rtol = 2.0e-16)
  MethodError: no method matching _nextfloat(::Measurement{Float64}, ::Bool, ::UInt64)
  The function `_nextfloat` exists, but no method is defined for this combination of argument types.
  
  Closest candidates are:
    _nextfloat(!Matched::Union{Float16, Float32, Float64}, ::Bool, ::Integer)
     @ Base float.jl:811
  
  Stacktrace:
   [1] prevfloat(x::Measurement{Float64}, d::Int64)
     @ Base ./float.jl:872
   [2] macro expansion
     @ /opt/julia/share/julia/stdlib/v1.12/Test/src/Test.jl:677 [inlined]
   [3] macro expansion
     @ ~/.julia/packages/Measurements/pivk0/test/runtests.jl:723 [inlined]
   [4] macro expansion
     @ /opt/julia/share/julia/stdlib/v1.12/Test/src/Test.jl:1776 [inlined]
   [5] top-level scope
     @ ~/.julia/packages/Measurements/pivk0/test/runtests.jl:718
Test Summary:     | Pass  Error  Total  Time
Machine precision |   14      1     15  3.2s
RNG of the outermost testset: Random.Xoshiro(0x0e3a33dd23d99956, 0x3f3eee0e33e3eedb, 0xb4c5a981cf374033, 0xb09260fd6f34e3d4, 0x27d3f47ed60be1b2)
ERROR: LoadError: Some tests did not pass: 14 passed, 0 failed, 1 errored, 0 broken.
in expression starting at /home/pkgeval/.julia/packages/Measurements/pivk0/test/runtests.jl:716

Out of an abundance of caution I will drop this from 1.12 backport. It can be put back after analysis or if it gets fixed.

@KristofferC KristofferC removed the backport 1.12 Change should be backported to release-1.12 label Oct 14, 2025
@adienes
Copy link
Member Author

adienes commented Oct 14, 2025

that seems to be due to this definition

Base.nextfloat(a::Measurement, n::Integer) = result(nextfloat(a.val, n), 1, a)

without a corresponding prevfloat, which is buggy. the bug was Base's fault, not the author's, but ultimately this is a "good" failure. fair to remove it from the backport though; this was status quo for like 10 years so I suppose another version doesn't really matter

@adienes
Copy link
Member Author

adienes commented Oct 14, 2025

#59836

applications of [`nextfloat`](@ref) if `n < 0`.
"""
prevfloat(x::AbstractFloat, d::Integer) = nextfloat(x, -d)
prevfloat(x::AbstractFloat, d::Integer) = _nextfloat(x, ispositive(d), uabs(d))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now packages defining custom AbstractFloat are expected to define a method for Base._nextfloat?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, they should define prevfloat separately and explicitly as the old fallback in Base was not correct, leading to behavior like

julia> prevfloat(Measurement{Float64}(1.0), 0x01)
1.0000000000000566 ± 0.0

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix This change fixes an existing bug maths Mathematical functions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Underflow in prevfloat with Unsigned iteration count

6 participants