Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nextfloat(::BigFloat, n), prevfloat(::BigFloat,n) #31310

Merged
merged 6 commits into from
Apr 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ New language features
`findall`, `findfirst`, `argmin`/`argmax` and `findmin`/`findmax` to work with these
objects, returning the index of matching non-missing elements in the parent ([#31008]).

* `inv(::Missing)` has now been added and returns `missing` ([#31408]).
* `inv(::Missing)` has now been added and returns `missing` ([#31451]).

* `nextfloat(::BigFloat, n::Integer)` and `prevfloat(::BigFloat, n::Integer)` methods
have been added ([#31310]).

Multi-threading changes
-----------------------
Expand Down Expand Up @@ -49,6 +52,9 @@ Standard library changes
* A no-argument construct to `Ptr{T}` has been added which constructs a null pointer ([#30919])
* `strip` now accepts a function argument in the same manner as `lstrip` and `rstrip` ([#31211])
* `mktempdir` now accepts a `prefix` keyword argument to customize the file name ([#31230], [#22922])
* `nextfloat(::BigFloat)` and `prevfloat(::BigFloat)` now returns a value with the same precision
as their argument, which means that (in particular) `nextfloat(prevfloat(x)) == x` whereas
previously this could result in a completely different value with a different precision ([#31310])

#### LinearAlgebra

Expand Down
2 changes: 1 addition & 1 deletion base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ uabs(x::BitSigned) = unsigned(abs(x))


"""
nextfloat(x::IEEEFloat, n::Integer)
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`.
Expand Down
35 changes: 23 additions & 12 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ function BigFloat(x::BigFloat, r::MPFRRoundingMode=ROUNDING_MODE[]; precision::I
end
end

function _duplicate(x::BigFloat)
z = BigFloat(;precision=precision(x))
ccall((:mpfr_set, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32), z, x, 0)
return z
end

# convert to BigFloat
for (fJ, fC) in ((:si,:Clong), (:ui,:Culong))
Expand Down Expand Up @@ -889,22 +894,25 @@ isone(x::BigFloat) = x == Clong(1)
@eval typemax(::Type{BigFloat}) = $(BigFloat(Inf))
@eval typemin(::Type{BigFloat}) = $(BigFloat(-Inf))

function nextfloat(x::BigFloat)
z = BigFloat()
ccall((:mpfr_set, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode),
z, x, ROUNDING_MODE[])
ccall((:mpfr_nextabove, :libmpfr), Int32, (Ref{BigFloat},), z) != 0
return z
function nextfloat!(x::BigFloat, n::Integer=1)
signbit(n) && return prevfloat!(x, abs(n))
for i = 1:n
ccall((:mpfr_nextabove, :libmpfr), Int32, (Ref{BigFloat},), x)
end
return x
end

function prevfloat(x::BigFloat)
z = BigFloat()
ccall((:mpfr_set, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode),
z, x, ROUNDING_MODE[])
ccall((:mpfr_nextbelow, :libmpfr), Int32, (Ref{BigFloat},), z) != 0
return z
function prevfloat!(x::BigFloat, n::Integer=1)
signbit(n) && return nextfloat!(x, abs(n))
for i = 1:n
ccall((:mpfr_nextbelow, :libmpfr), Int32, (Ref{BigFloat},), x)
end
return x
end

nextfloat(x::BigFloat, n::Integer=1) = n == 0 ? x : nextfloat!(_duplicate(x), n)
prevfloat(x::BigFloat, n::Integer=1) = n == 0 ? x : prevfloat!(_duplicate(x), n)

eps(::Type{BigFloat}) = nextfloat(BigFloat(1)) - BigFloat(1)

floatmin(::Type{BigFloat}) = nextfloat(zero(BigFloat))
Expand All @@ -922,6 +930,9 @@ It is logically equivalent to:
setprecision(BigFloat, old)

Often used as `setprecision(T, precision) do ... end`

Note: `nextfloat()`, `prevfloat()` do not use the precision mentioned by
`setprecision`
"""
function setprecision(f::Function, ::Type{T}, prec::Integer) where T
old_prec = precision(T)
Expand Down
13 changes: 13 additions & 0 deletions test/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,21 @@ end
@test BigFloat(nextfloat(12.12)) == nextfloat(x)
@test BigFloat(prevfloat(12.12)) == prevfloat(x)
end
x = BigFloat(12.12, 100)
@test nextfloat(x, 0) === x
@test prevfloat(x, 0) === x
@test nextfloat(x).prec == x.prec
@test prevfloat(x).prec == x.prec
@test nextfloat(x) == nextfloat(x, 1)
@test prevfloat(x) == prevfloat(x, 1)
@test nextfloat(x, -1) == prevfloat(x, 1)
@test nextfloat(x, -2) == prevfloat(x, 2)
@test prevfloat(x, -1) == nextfloat(x, 1)
@test prevfloat(x, -2) == nextfloat(x, 2)
@test isnan(nextfloat(BigFloat(NaN)))
@test isnan(prevfloat(BigFloat(NaN)))
@test isnan(nextfloat(BigFloat(NaN), 1))
@test isnan(prevfloat(BigFloat(NaN), 1))
end
# sqrt DomainError
@test_throws DomainError sqrt(BigFloat(-1))
Expand Down