From c6ba0e9e1f9bf0f564b2a36a4da09131d3bc569c Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Fri, 30 Mar 2018 13:15:30 -0700 Subject: [PATCH 01/18] change combine signif into round --- base/floatfuncs.jl | 177 +++++++++++++++++++++------------------------ 1 file changed, 82 insertions(+), 95 deletions(-) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 249c4ee4204fd..6df472dd2661e 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -44,43 +44,52 @@ isinteger(x::AbstractFloat) = (x - trunc(x) == 0) """ round([T,] x, [r::RoundingMode]) - round(x, [digits; base = 10]) + round(x, [r::RoundingMode]; digits::Integer[, base = 10]) + round(x, [r::RoundingMode]; sigdigits::Integer[, base = 10]) + +Rounds the number `x`. + +Without keyword arguments, `x` is rounded to an integer value, returning a value of type +`T`, or of the same type of `x` if no `T` is provided. An [`InexactError`](@ref) will be +thrown if the value is not representable by `T`, similar to [`convert`](@ref). + +If the `digits` keyword argument is provied, it rounds to the specified number of digits +after the decimal place (or before if negative), in base `base`. + +If the `sigdigits` keyword argument is provided, it rounds to the specified number of +significant digits, in base `base`. + +The [`RoundingMode`](@ref) `r` controls the direction of the rounding: when no rounding +mode is specified, the global mode will be used (see [`rounding`](@ref)), which by default +is round to the nearest integer ([`RoundNearest`](@ref) mode), with ties (fractional +values of 0.5) being rounded to the nearest even integer. -Rounds `x` to an integer value according to the provided -[`RoundingMode`](@ref), returning a value of the same type as `x`. When not -specifying a rounding mode the global mode will be used -(see [`rounding`](@ref)), which by default is round to the nearest integer -([`RoundNearest`](@ref) mode), with ties (fractional values of 0.5) being -rounded to the nearest even integer. # Examples ```jldoctest julia> round(1.7) 2.0 +julia> round(Int, 1.7) +2 + julia> round(1.5) 2.0 julia> round(2.5) 2.0 -``` -The optional [`RoundingMode`](@ref) argument will change how the number gets -rounded. - -`round(T, x, [r::RoundingMode])` converts the result to type `T`, throwing an -[`InexactError`](@ref) if the value is not representable. - -`round(x, digits)` rounds to the specified number of digits after the decimal place (or -before if negative). `round(x, digits, base = base)` rounds using a base other than 10. - -# Examples -```jldoctest -julia> round(pi, 2) +julia> round(pi; digits=2) 3.14 -julia> round(pi, 3, base = 2) +julia> round(pi; digits=3, base=2) 3.125 + +julia> round(123.456; sigdigits=2) +120.0 + +julia> round(357.913; sigdigits=4, base=2) +352.0 ``` !!! note @@ -104,93 +113,71 @@ julia> round(pi, 3, base = 2) 1.2 ``` -See also [`signif`](@ref) for rounding to significant digits. +# Extensions + +To extend `round` to new numeric types, it is typically sufficient to define `Base._round(x::NewType, ::RoundingMode)`. """ round(T::Type, x) -round(x::Real, ::RoundingMode{:ToZero}) = trunc(x) -round(x::Real, ::RoundingMode{:Up}) = ceil(x) -round(x::Real, ::RoundingMode{:Down}) = floor(x) -# C-style round -function round(x::AbstractFloat, ::RoundingMode{:NearestTiesAway}) - y = trunc(x) - ifelse(x==y,y,trunc(2*x-y)) -end -# Java-style round -function round(x::AbstractFloat, ::RoundingMode{:NearestTiesUp}) - y = floor(x) - ifelse(x==y,y,copysign(floor(2*x-y),x)) -end + +round(::Type{T}, x::AbstractFloat, r::RoundingMode{:ToZero}) where {T<:Integer} = trunc(T, x) round(::Type{T}, x::AbstractFloat, r::RoundingMode) where {T<:Integer} = trunc(T,round(x,r)) -# adapted from Matlab File Exchange roundsd: http://www.mathworks.com/matlabcentral/fileexchange/26212 -# for round, og is the power of 10 relative to the decimal point -# for signif, og is the absolute power of 10 -# digits and base must be integers, x must be convertable to float - -function _signif_og(x, digits, base) - if base == 10 - e = floor(log10(abs(x)) - digits + 1.) - og = oftype(x, exp10(abs(e))) - elseif base == 2 - e = exponent(abs(x)) - digits + 1. - og = oftype(x, exp2(abs(e))) +function round(x, r::RoundingMode=RoundNearest; + digits::Union{Nothing,Integer}=nothing, sigdigits::Union{Nothing,Integer}=nothing, base=10) + _round(x,r,digits,sigdigits,base) +end +_round(x, r::RoundingMode, digits::Nothing, sigdigits::Nothing, base) = _round(x, r) + +function _round(x, r::RoundingMode, digits::Integer, sigdigits::Nothing, base) + fx = float(x) + if digits >= 0 + sc = oftype(fx, base)^digits + r = round(fx * sc, r) / sc else - e = floor(log(base, abs(x)) - digits + 1.) - og = oftype(x, float(base) ^ abs(e)) + isc = oftype(fx, base)^-digits + r = round(fx / isc, r) * isc end - return og, e + + if !isfinite(r) + if digits > 0 + return fx + elseif x > 0 + return (r == RoundUp ? oftype(x, Inf) : zero(fx)) + elseif x < 0 + return (r == RoundDown ? -oftype(x, Inf) : -zero(fx)) + else + return fx + end + end + return r end -""" - signif(x, digits; base = 10) - -Rounds (in the sense of [`round`](@ref)) `x` so that there are `digits` significant digits, under a -base `base` representation, default 10. -# Examples -```jldoctest -julia> signif(123.456, 2) -120.0 - -julia> signif(357.913, 4, base = 2) -352.0 -``` -""" -function signif(x::Real, digits::Integer; base::Integer = 10) - digits < 1 && throw(DomainError(digits, "`digits` cannot be less than 1.")) - - x = float(x) - (x == 0 || !isfinite(x)) && return x - og, e = _signif_og(x, digits, base) - if e >= 0 # for numeric stability - r = round(x/og)*og +function _round(x, r::RoundingMode, digits::Nothing, sigdigits::Integer, base) + fx = float(x) + if base == 2 + hidig = 1 + exponent(x) + elseif base == 10 + hidig = 1 + floor(Int, log10(abs(fx))) else - r = round(x*og)/og + hidig = 1 + floor(Int, log(abs(fx), base)) end - !isfinite(r) ? x : r + _round(fx, r, sigdigits-hidig, nothing, base) end -for f in (:round, :ceil, :floor, :trunc) - @eval begin - function ($f)(x::Real, digits::Integer; base::Integer = 10) - x = float(x) - og = convert(eltype(x),base)^digits - r = ($f)(x * og) / og - - if !isfinite(r) - if digits > 0 - return x - elseif x > 0 - return $(:ceil == f ? :(convert(eltype(x), Inf)) : :(zero(x))) - elseif x < 0 - return $(:floor == f ? :(-convert(eltype(x), Inf)) : :(-zero(x))) - else - return x - end - end - return r - end - end +_round(x, r::RoundingMode, digits::Integer, sigdigits::Integer, base) = + throw(ArgumentError("`round` cannot use both `digits` and `sigdigits` arguments.") + + +# C-style round +function _round(x::AbstractFloat, ::RoundingMode{:NearestTiesAway}) + y = trunc(x) + ifelse(x==y,y,trunc(2*x-y)) +end +# Java-style round +function _round(x::AbstractFloat, ::RoundingMode{:NearestTiesUp}) + y = floor(x) + ifelse(x==y,y,copysign(floor(2*x-y),x)) end # isapprox: approximate equality of numbers From 281c5500e87c9f8f1ca21df09038c0b6d93b1e22 Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Fri, 30 Mar 2018 14:24:51 -0700 Subject: [PATCH 02/18] deprecate signif, move round digits/sigdigits to kwargs --- base/deprecated.jl | 16 +++++++++----- base/exports.jl | 1 - base/float.jl | 55 +++++++++++++++++++--------------------------- base/floatfuncs.jl | 42 ++++++++++++++++++++--------------- base/int.jl | 23 +++++++++---------- 5 files changed, 69 insertions(+), 68 deletions(-) diff --git a/base/deprecated.jl b/base/deprecated.jl index 4ad071716d703..2d0bdc5b08897 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1500,11 +1500,17 @@ end false) # PR 26156 -@deprecate trunc(x, digits, base) trunc(x, digits, base = base) -@deprecate floor(x, digits, base) floor(x, digits, base = base) -@deprecate ceil(x, digits, base) ceil(x, digits, base = base) -@deprecate round(x, digits, base) round(x, digits, base = base) -@deprecate signif(x, digits, base) signif(x, digits, base = base) +@deprecate trunc(x, digits) trunc(x; digits=digits) +@deprecate floor(x, digits) floor(x; digits=digits) +@deprecate ceil(x, digits) ceil(x; digits=digits) +@deprecate round(x, digits) round(x; digits=digits) +@deprecate signif(x, digits) round(x; sigdigits=digits, base = base) + +@deprecate trunc(x, digits, base) trunc(x; digits=digits, base = base) +@deprecate floor(x, digits, base) floor(x; digits=digits, base = base) +@deprecate ceil(x, digits, base) ceil(x; digits=digits, base = base) +@deprecate round(x, digits, base) round(x; digits=digits, base = base) +@deprecate signif(x, digits, base) round(x; sigdigits=digits, base = base) # issue #25965 @deprecate spawn(cmds::AbstractCmd) run(cmds, wait = false) diff --git a/base/exports.jl b/base/exports.jl index 15de30529884f..da60509c29b9a 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -324,7 +324,6 @@ export sign, signbit, signed, - signif, significand, sin, sinc, diff --git a/base/float.jl b/base/float.jl index f39d9a3679816..4c1916103e7b5 100644 --- a/base/float.jl +++ b/base/float.jl @@ -337,39 +337,28 @@ end unsafe_trunc(::Type{UInt128}, x::Float16) = unsafe_trunc(UInt128, Float32(x)) unsafe_trunc(::Type{Int128}, x::Float16) = unsafe_trunc(Int128, Float32(x)) -# matches convert methods -# also determines floor, ceil, round -trunc(::Type{Signed}, x::Float32) = trunc(Int,x) -trunc(::Type{Signed}, x::Float64) = trunc(Int,x) -trunc(::Type{Unsigned}, x::Float32) = trunc(UInt,x) -trunc(::Type{Unsigned}, x::Float64) = trunc(UInt,x) -trunc(::Type{Integer}, x::Float32) = trunc(Int,x) -trunc(::Type{Integer}, x::Float64) = trunc(Int,x) -trunc(::Type{T}, x::Float16) where {T<:Integer} = trunc(T, Float32(x)) - -# fallbacks -floor(::Type{T}, x::AbstractFloat) where {T<:Integer} = trunc(T,floor(x)) -floor(::Type{T}, x::Float16) where {T<:Integer} = floor(T, Float32(x)) -ceil(::Type{T}, x::AbstractFloat) where {T<:Integer} = trunc(T,ceil(x)) -ceil(::Type{T}, x::Float16) where {T<:Integer} = ceil(T, Float32(x)) -round(::Type{T}, x::AbstractFloat) where {T<:Integer} = trunc(T,round(x)) -round(::Type{T}, x::Float16) where {T<:Integer} = round(T, Float32(x)) - -trunc(x::Float64) = trunc_llvm(x) -trunc(x::Float32) = trunc_llvm(x) -trunc(x::Float16) = Float16(trunc(Float32(x))) - -floor(x::Float64) = floor_llvm(x) -floor(x::Float32) = floor_llvm(x) -floor(x::Float16) = Float16(floor(Float32(x))) - -ceil(x::Float64) = ceil_llvm(x) -ceil(x::Float32) = ceil_llvm(x) -ceil(x::Float16) = Float16( ceil(Float32(x))) - -round(x::Float64) = rint_llvm(x) -round(x::Float32) = rint_llvm(x) -round(x::Float16) = Float16(round(Float32(x))) +_round(x::Float64, r::RoundingMode{:ToZero}) = trunc_llvm(x) +_round(x::Float32, r::RoundingMode{:ToZero}) = trunc_llvm(x) +_round(x::Float64, r::RoundingMode{:Down}) = floor_llvm(x) +_round(x::Float32, r::RoundingMode{:Down}) = floor_llvm(x) +_round(x::Float64, r::RoundingMode{:Up}) = ceil_llvm(x) +_round(x::Float32, r::RoundingMode{:Up}) = ceil_llvm(x) +_round(x::Float64, r::RoundingMode{:Nearest}) = rint_llvm(x) +_round(x::Float32, r::RoundingMode{:Nearest}) = rint_llvm(x) + +_round(x::Float16, r::RoundingMode) = Float16(round(Float32(x, r))) + +# all float -> integer conversions are defined in terms of `trunc` +trunc(::Type{Signed}, x) = trunc(Int, x) +trunc(::Type{Unsigned}, x) = trunc(UInt,x) +trunc(::Type{Integer}, x) = trunc(Int, x) + +round(::Type{T}, x::AbstractFloat, r::RoundingMode) where {T<:Integer} = + trunc(T, _round(x, r)) +ceil(::Type{T}, x::AbstractFloat) = round(T, x, RoundUp) +floor(::Type{T}, x::AbstractFloat) = round(T, x, RoundDown) +round(::Type{T}, x::AbstractFloat) = round(T, x, RoundNearest) + ## floating point promotions ## promote_rule(::Type{Float32}, ::Type{Float16}) = Float32 diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 6df472dd2661e..06e5f76617580 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -44,8 +44,8 @@ isinteger(x::AbstractFloat) = (x - trunc(x) == 0) """ round([T,] x, [r::RoundingMode]) - round(x, [r::RoundingMode]; digits::Integer[, base = 10]) - round(x, [r::RoundingMode]; sigdigits::Integer[, base = 10]) + round(x, [r::RoundingMode]; digits::Integer= [, base = 10]) + round(x, [r::RoundingMode]; sigdigits::Integer= [, base = 10]) Rounds the number `x`. @@ -59,11 +59,10 @@ after the decimal place (or before if negative), in base `base`. If the `sigdigits` keyword argument is provided, it rounds to the specified number of significant digits, in base `base`. -The [`RoundingMode`](@ref) `r` controls the direction of the rounding: when no rounding -mode is specified, the global mode will be used (see [`rounding`](@ref)), which by default -is round to the nearest integer ([`RoundNearest`](@ref) mode), with ties (fractional -values of 0.5) being rounded to the nearest even integer. - +The [`RoundingMode`](@ref) `r` controls the direction of the rounding; the default is +[`RoundNearest`](@ref), which rounds to the nearest integer, with ties (fractional values +of 0.5) being rounded to the nearest even integer. Note that `round` may give incorrect +results if the global rounding mode is changed (see [`rounding`](@ref)). # Examples ```jldoctest @@ -120,16 +119,20 @@ To extend `round` to new numeric types, it is typically sufficient to define `Ba round(T::Type, x) round(::Type{T}, x::AbstractFloat, r::RoundingMode{:ToZero}) where {T<:Integer} = trunc(T, x) -round(::Type{T}, x::AbstractFloat, r::RoundingMode) where {T<:Integer} = trunc(T,round(x,r)) +round(::Type{T}, x::AbstractFloat, r::RoundingMode) where {T<:Integer} = trunc(T, _round(x,r)) function round(x, r::RoundingMode=RoundNearest; digits::Union{Nothing,Integer}=nothing, sigdigits::Union{Nothing,Integer}=nothing, base=10) _round(x,r,digits,sigdigits,base) end +trunc(x; kwargs...) = round(x, RoundToZero; kwargs...) +floor(x; kwargs...) = round(x, RoundDown; kwargs...) +ceil(x; kwargs...) = round(x, RoundUp; kwargs...) + _round(x, r::RoundingMode, digits::Nothing, sigdigits::Nothing, base) = _round(x, r) +_round(x::Integer, r::RoundingMode) = x function _round(x, r::RoundingMode, digits::Integer, sigdigits::Nothing, base) - fx = float(x) if digits >= 0 sc = oftype(fx, base)^digits r = round(fx * sc, r) / sc @@ -152,23 +155,26 @@ function _round(x, r::RoundingMode, digits::Integer, sigdigits::Nothing, base) return r end - -function _round(x, r::RoundingMode, digits::Nothing, sigdigits::Integer, base) +hidigit(x::Integer, base) = ndigits0z(x, base) +function hidigit(x::Real, base) fx = float(x) - if base == 2 - hidig = 1 + exponent(x) - elseif base == 10 - hidig = 1 + floor(Int, log10(abs(fx))) + if base == 10 + return 1 + floor(Int, log10(abs(fx))) + elseif base == 2 + return 1 + exponent(x) else - hidig = 1 + floor(Int, log(abs(fx), base)) + return 1 + floor(Int, log(abs(fx), base)) end - _round(fx, r, sigdigits-hidig, nothing, base) +end + +function _round(x, r::RoundingMode, digits::Nothing, sigdigits::Integer, base) + h = hidigit(x, base) + _round(x, r, sigdigits-h, nothing, base) end _round(x, r::RoundingMode, digits::Integer, sigdigits::Integer, base) = throw(ArgumentError("`round` cannot use both `digits` and `sigdigits` arguments.") - # C-style round function _round(x::AbstractFloat, ::RoundingMode{:NearestTiesAway}) y = trunc(x) diff --git a/base/int.jl b/base/int.jl index 406fbc62ca052..c83345cc75b06 100644 --- a/base/int.jl +++ b/base/int.jl @@ -492,7 +492,9 @@ mod(x::Integer, ::Type{T}) where {T<:Integer} = rem(x, T) unsafe_trunc(::Type{T}, x::Integer) where {T<:Integer} = rem(x, T) """ - trunc([T,] x, [digits; base = 10]) + trunc([T,] x) + trunc(x; digits::Integer= [, base = 10]) + trunc(x; sigdigits::Integer= [, base = 10]) `trunc(x)` returns the nearest integral value of the same type as `x` whose absolute value is less than or equal to `x`. @@ -500,12 +502,14 @@ is less than or equal to `x`. `trunc(T, x)` converts the result to type `T`, throwing an `InexactError` if the value is not representable. -`digits` and `base` work as for [`round`](@ref). +`digits`, `sigdigits` and `base` work as for [`round`](@ref). """ function trunc end """ - floor([T,] x, [digits; base = 10]) + floor([T,] x) + floor(x; digits::Integer= [, base = 10]) + floor(x; sigdigits::Integer= [, base = 10]) `floor(x)` returns the nearest integral value of the same type as `x` that is less than or equal to `x`. @@ -513,12 +517,14 @@ equal to `x`. `floor(T, x)` converts the result to type `T`, throwing an `InexactError` if the value is not representable. -`digits` and `base` work as for [`round`](@ref). +`digits`, `sigdigits` and `base` work as for [`round`](@ref). """ function floor end """ - ceil([T,] x, [digits; base = 10]) + ceil([T,] x) + ceil(x; digits::Integer= [, base = 10]) + ceil(x; sigdigits::Integer= [, base = 10]) `ceil(x)` returns the nearest integral value of the same type as `x` that is greater than or equal to `x`. @@ -526,15 +532,10 @@ equal to `x`. `ceil(T, x)` converts the result to type `T`, throwing an `InexactError` if the value is not representable. -`digits` and `base` work as for [`round`](@ref). +`digits`, `sigdigits` and `base` work as for [`round`](@ref). """ function ceil end -round(x::Integer) = x -trunc(x::Integer) = x -floor(x::Integer) = x - ceil(x::Integer) = x - round(::Type{T}, x::Integer) where {T<:Integer} = convert(T, x) trunc(::Type{T}, x::Integer) where {T<:Integer} = convert(T, x) floor(::Type{T}, x::Integer) where {T<:Integer} = convert(T, x) From 29eedee16e57b8f221fe257f2dbd18ea7ed1e1c1 Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Fri, 30 Mar 2018 14:54:13 -0700 Subject: [PATCH 03/18] fix bootsrapping --- base/float.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/base/float.jl b/base/float.jl index 4c1916103e7b5..fdd61502ee879 100644 --- a/base/float.jl +++ b/base/float.jl @@ -355,6 +355,7 @@ trunc(::Type{Integer}, x) = trunc(Int, x) round(::Type{T}, x::AbstractFloat, r::RoundingMode) where {T<:Integer} = trunc(T, _round(x, r)) + ceil(::Type{T}, x::AbstractFloat) = round(T, x, RoundUp) floor(::Type{T}, x::AbstractFloat) = round(T, x, RoundDown) round(::Type{T}, x::AbstractFloat) = round(T, x, RoundNearest) @@ -651,7 +652,7 @@ for Ti in (Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UIn end end function (::Type{$Ti})(x::$Tf) - if ($(Tf(typemin(Ti))) <= x <= $(Tf(typemax(Ti)))) && (trunc(x) == x) + if ($(Tf(typemin(Ti))) <= x <= $(Tf(typemax(Ti)))) && (_round(x, RoundToZero) == x) return unsafe_trunc($Ti,x) else throw(InexactError($(Expr(:quote,Ti.name.name)), $Ti, x)) @@ -672,7 +673,7 @@ for Ti in (Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UIn end end function (::Type{$Ti})(x::$Tf) - if ($(Tf(typemin(Ti))) <= x < $(Tf(typemax(Ti)))) && (trunc(x) == x) + if ($(Tf(typemin(Ti))) <= x < $(Tf(typemax(Ti)))) && (_round(x, RoundToZero) == x) return unsafe_trunc($Ti,x) else throw(InexactError($(Expr(:quote,Ti.name.name)), $Ti, x)) From d5d843bcf9bf589822eb5f96fc0625c0ee29ce5f Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Fri, 30 Mar 2018 18:49:06 -0400 Subject: [PATCH 04/18] rejig to get building --- base/float.jl | 32 +++++++++++++++++++------------- base/floatfuncs.jl | 2 +- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/base/float.jl b/base/float.jl index fdd61502ee879..ec843b4b68faf 100644 --- a/base/float.jl +++ b/base/float.jl @@ -337,6 +337,24 @@ end unsafe_trunc(::Type{UInt128}, x::Float16) = unsafe_trunc(UInt128, Float32(x)) unsafe_trunc(::Type{Int128}, x::Float16) = unsafe_trunc(Int128, Float32(x)) +# matches convert methods +# also determines floor, ceil, round +trunc(::Type{Signed}, x::Float32) = trunc(Int,x) +trunc(::Type{Signed}, x::Float64) = trunc(Int,x) +trunc(::Type{Unsigned}, x::Float32) = trunc(UInt,x) +trunc(::Type{Unsigned}, x::Float64) = trunc(UInt,x) +trunc(::Type{Integer}, x::Float32) = trunc(Int,x) +trunc(::Type{Integer}, x::Float64) = trunc(Int,x) +trunc(::Type{T}, x::Float16) where {T<:Integer} = trunc(T, Float32(x)) + +# fallbacks +floor(::Type{T}, x::AbstractFloat) where {T<:Integer} = trunc(T,_round(x, RoundDown)) +floor(::Type{T}, x::Float16) where {T<:Integer} = floor(T, Float32(x)) +ceil(::Type{T}, x::AbstractFloat) where {T<:Integer} = trunc(T,_round(x, RoundUp)) +ceil(::Type{T}, x::Float16) where {T<:Integer} = ceil(T, Float32(x)) +round(::Type{T}, x::AbstractFloat) where {T<:Integer} = trunc(T,_round(x, RoundNearest)) +round(::Type{T}, x::Float16) where {T<:Integer} = round(T, Float32(x)) + _round(x::Float64, r::RoundingMode{:ToZero}) = trunc_llvm(x) _round(x::Float32, r::RoundingMode{:ToZero}) = trunc_llvm(x) _round(x::Float64, r::RoundingMode{:Down}) = floor_llvm(x) @@ -346,19 +364,7 @@ _round(x::Float32, r::RoundingMode{:Up}) = ceil_llvm(x) _round(x::Float64, r::RoundingMode{:Nearest}) = rint_llvm(x) _round(x::Float32, r::RoundingMode{:Nearest}) = rint_llvm(x) -_round(x::Float16, r::RoundingMode) = Float16(round(Float32(x, r))) - -# all float -> integer conversions are defined in terms of `trunc` -trunc(::Type{Signed}, x) = trunc(Int, x) -trunc(::Type{Unsigned}, x) = trunc(UInt,x) -trunc(::Type{Integer}, x) = trunc(Int, x) - -round(::Type{T}, x::AbstractFloat, r::RoundingMode) where {T<:Integer} = - trunc(T, _round(x, r)) - -ceil(::Type{T}, x::AbstractFloat) = round(T, x, RoundUp) -floor(::Type{T}, x::AbstractFloat) = round(T, x, RoundDown) -round(::Type{T}, x::AbstractFloat) = round(T, x, RoundNearest) +_round(x::Float16, r::RoundingMode) = Float16(_round(Float32(x), r)) ## floating point promotions ## diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 06e5f76617580..475af43812bf5 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -173,7 +173,7 @@ function _round(x, r::RoundingMode, digits::Nothing, sigdigits::Integer, base) end _round(x, r::RoundingMode, digits::Integer, sigdigits::Integer, base) = - throw(ArgumentError("`round` cannot use both `digits` and `sigdigits` arguments.") + throw(ArgumentError("`round` cannot use both `digits` and `sigdigits` arguments.")) # C-style round function _round(x::AbstractFloat, ::RoundingMode{:NearestTiesAway}) From 3ffc9466fcca44d0ad71b674108cf079b169e03d Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Fri, 30 Mar 2018 15:54:05 -0700 Subject: [PATCH 05/18] modify tests --- test/floatfuncs.jl | 40 +++++++++++----------- test/rounding.jl | 82 +++++++++++++++++++++++----------------------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/test/floatfuncs.jl b/test/floatfuncs.jl index 00f1b25794154..36457118929c1 100644 --- a/test/floatfuncs.jl +++ b/test/floatfuncs.jl @@ -79,24 +79,24 @@ end @testset "significant digits" begin # (would be nice to have a smart vectorized # version of signif) - @test signif(123.456, 1) ≈ 100. - @test signif(123.456, 3) ≈ 123. - @test signif(123.456, 5) ≈ 123.46 - @test signif(123.456, 8, base = 2) ≈ 123.5 - @test signif(123.456, 2, base = 4) ≈ 128.0 - @test signif(0.0, 1) === 0.0 - @test signif(-0.0, 1) === -0.0 - @test signif(1.2, 2) === 1.2 - @test signif(1.0, 6) === 1.0 - @test signif(0.6, 1) === 0.6 - @test signif(7.262839104539736, 2) === 7.3 - @test isinf(signif(Inf, 3)) - @test isnan(signif(NaN, 3)) - @test signif(1.12312, 1000) === 1.12312 - @test signif(Float32(7.262839104539736), 3) === Float32(7.26) - @test signif(Float32(7.262839104539736), 4) === Float32(7.263) - @test signif(Float32(1.2), 3) === Float32(1.2) - @test signif(Float32(1.2), 5) === Float32(1.2) - @test signif(Float16(0.6), 2) === Float16(0.6) - @test signif(Float16(1.1), 70) === Float16(1.1) + @test round(123.456, sigdigits=1) ≈ 100. + @test round(123.456, sigdigits=3) ≈ 123. + @test round(123.456, sigdigits=5) ≈ 123.46 + @test round(123.456, sigdigits=8, base = 2) ≈ 123.5 + @test round(123.456, sigdigits=2, base = 4) ≈ 128.0 + @test round(0.0, sigdigits=1) === 0.0 + @test round(-0.0, sigdigits=1) === -0.0 + @test round(1.2, sigdigits=2) === 1.2 + @test round(1.0, sigdigits=6) === 1.0 + @test round(0.6, sigdigits=1) === 0.6 + @test round(7.262839104539736, sigdigits=2) === 7.3 + @test isinf(round(Inf, sigdigits=3)) + @test isnan(round(NaN, sigdigits=3)) + @test round(1.12312, sigdigits=1000) === 1.12312 + @test round(Float32(7.262839104539736), sigdigits=3) === Float32(7.26) + @test round(Float32(7.262839104539736), sigdigits=4) === Float32(7.263) + @test round(Float32(1.2), sigdigits=3) === Float32(1.2) + @test round(Float32(1.2), sigdigits=5) === Float32(1.2) + @test round(Float16(0.6), sigdigits=2) === Float16(0.6) + @test round(Float16(1.1), sigdigits=70) === Float16(1.1) end diff --git a/test/rounding.jl b/test/rounding.jl index fe6779e382cc2..c7b0c9dde2864 100644 --- a/test/rounding.jl +++ b/test/rounding.jl @@ -265,65 +265,65 @@ end # custom rounding and significant-digit ops @testset "rounding to digits relative to the decimal point" begin - @test round(pi,0) ≈ 3. - @test round(pi,1) ≈ 3.1 - @test round(10*pi,-1) ≈ 30. - @test round(.1,0) == 0. - @test round(-.1,0) == -0. - @test isnan(round(NaN, 2)) - @test isinf(round(Inf,2)) - @test isinf(round(-Inf,2)) + @test round(pi, digits=0) ≈ 3. + @test round(pi, digits=1) ≈ 3.1 + @test round(10*pi, digits=-1) ≈ 30. + @test round(.1, digits=0) == 0. + @test round(-.1, digits=0) == -0. + @test isnan(round(NaN, digits=2)) + @test isinf(round(Inf, digits=2)) + @test isinf(round(-Inf, digits=2)) end @testset "round vs trunc vs floor vs ceil" begin - @test round(123.456,1) ≈ 123.5 - @test round(-123.456,1) ≈ -123.5 - @test trunc(123.456,1) ≈ 123.4 - @test trunc(-123.456,1) ≈ -123.4 - @test ceil(123.456,1) ≈ 123.5 - @test ceil(-123.456,1) ≈ -123.4 - @test floor(123.456,1) ≈ 123.4 - @test floor(-123.456,1) ≈ -123.5 + @test round(123.456, digits=1) ≈ 123.5 + @test round(-123.456, digits=1) ≈ -123.5 + @test trunc(123.456, digits=1) ≈ 123.4 + @test trunc(-123.456, digits=1) ≈ -123.4 + @test ceil(123.456, digits=1) ≈ 123.5 + @test ceil(-123.456, digits=1) ≈ -123.4 + @test floor(123.456, digits=1) ≈ 123.4 + @test floor(-123.456, digits=1) ≈ -123.5 end @testset "rounding with too much (or too few) precision" begin for x in (12345.6789, 0, -12345.6789) y = float(x) - @test y == trunc(x, 1000) - @test y == round(x, 1000) - @test y == floor(x, 1000) - @test y == ceil(x, 1000) + @test y == trunc(x, digits=1000) + @test y == round(x, digits=1000) + @test y == floor(x, digits=1000) + @test y == ceil(x, digits=1000) end let x = 12345.6789 - @test 0.0 == trunc(x, -1000) - @test 0.0 == round(x, -1000) - @test 0.0 == floor(x, -1000) - @test Inf == ceil(x, -1000) + @test 0.0 == trunc(x, digits=-1000) + @test 0.0 == round(x, digits=-1000) + @test 0.0 == floor(x, digits=-1000) + @test Inf == ceil(x, digits=-1000) end let x = -12345.6789 - @test -0.0 == trunc(x, -1000) - @test -0.0 == round(x, -1000) - @test -Inf == floor(x, -1000) - @test -0.0 == ceil(x, -1000) + @test -0.0 == trunc(x, digits=-1000) + @test -0.0 == round(x, digits=-1000) + @test -Inf == floor(x, digits=-1000) + @test -0.0 == ceil(x, digits=-1000) end let x = 0.0 - @test 0.0 == trunc(x, -1000) - @test 0.0 == round(x, -1000) - @test 0.0 == floor(x, -1000) - @test 0.0 == ceil(x, -1000) + @test 0.0 == trunc(x, digits=-1000) + @test 0.0 == round(x, digits=-1000) + @test 0.0 == floor(x, digits=-1000) + @test 0.0 == ceil(x, digits=-1000) end end @testset "rounding in other bases" begin - @test round(pi, 2, base = 2) ≈ 3.25 - @test round(pi, 3, base = 2) ≈ 3.125 - @test round(pi, 3, base = 5) ≈ 3.144 + @test round(pi, digits = 2, base = 2) ≈ 3.25 + @test round(pi, digits = 3, base = 2) ≈ 3.125 + @test round(pi, digits = 3, base = 5) ≈ 3.144 end @testset "vectorized trunc/round/floor/ceil with digits/base argument" begin a = rand(2, 2, 2) for f in (round, trunc, floor, ceil) - @test f.(a[:, 1, 1], 2) == map(x->f(x, 2), a[:, 1, 1]) - @test f.(a[:, :, 1], 2) == map(x->f(x, 2), a[:, :, 1]) - @test f.(a, 9, base = 2) == map(x->f(x, 9, base = 2), a) - @test f.(a[:, 1, 1], 9, base = 2) == map(x->f(x, 9, base = 2), a[:, 1, 1]) - @test f.(a[:, :, 1], 9, base = 2) == map(x->f(x, 9, base = 2), a[:, :, 1]) - @test f.(a, 9, base = 2) == map(x->f(x, 9, base = 2), a) + @test f.(a[:, 1, 1], digits=2) == map(x->f(x, digits=2), a[:, 1, 1]) + @test f.(a[:, :, 1], digits=2) == map(x->f(x, digits=2), a[:, :, 1]) + @test f.(a, digits=9, base = 2) == map(x->f(x, digits=9, base = 2), a) + @test f.(a[:, 1, 1], digits=9, base = 2) == map(x->f(x, digits=9, base = 2), a[:, 1, 1]) + @test f.(a[:, :, 1], digits=9, base = 2) == map(x->f(x, digits=9, base = 2), a[:, :, 1]) + @test f.(a, digits=9, base = 2) == map(x->f(x, digits=9, base = 2), a) end end From 3346e2af6863acf6fb8163483ba7a2d7a19fc233 Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Fri, 30 Mar 2018 15:56:33 -0700 Subject: [PATCH 06/18] remove whitespace --- base/floatfuncs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 475af43812bf5..beaea4e29d63f 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -140,7 +140,7 @@ function _round(x, r::RoundingMode, digits::Integer, sigdigits::Nothing, base) isc = oftype(fx, base)^-digits r = round(fx / isc, r) * isc end - + if !isfinite(r) if digits > 0 return fx From 7ed448be5062c7664cbdda6c8e642b5f7481a25d Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Sat, 31 Mar 2018 02:13:38 -0400 Subject: [PATCH 07/18] fix tests --- base/floatfuncs.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index beaea4e29d63f..cb6a08eb5ffc1 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -123,6 +123,7 @@ round(::Type{T}, x::AbstractFloat, r::RoundingMode) where {T<:Integer} = trunc(T function round(x, r::RoundingMode=RoundNearest; digits::Union{Nothing,Integer}=nothing, sigdigits::Union{Nothing,Integer}=nothing, base=10) + isfinite(x) || return x _round(x,r,digits,sigdigits,base) end trunc(x; kwargs...) = round(x, RoundToZero; kwargs...) @@ -133,6 +134,7 @@ _round(x, r::RoundingMode, digits::Nothing, sigdigits::Nothing, base) = _round(x _round(x::Integer, r::RoundingMode) = x function _round(x, r::RoundingMode, digits::Integer, sigdigits::Nothing, base) + fx = float(x) if digits >= 0 sc = oftype(fx, base)^digits r = round(fx * sc, r) / sc @@ -157,13 +159,14 @@ end hidigit(x::Integer, base) = ndigits0z(x, base) function hidigit(x::Real, base) + iszero(x) && return 0 fx = float(x) if base == 10 return 1 + floor(Int, log10(abs(fx))) elseif base == 2 return 1 + exponent(x) else - return 1 + floor(Int, log(abs(fx), base)) + return 1 + floor(Int, log(base, abs(fx))) end end From aec787e1c5507f8655070fb0b58d559cf79c09da Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Sat, 31 Mar 2018 22:12:53 -0700 Subject: [PATCH 08/18] Float16 ambiguity problems --- base/float.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/base/float.jl b/base/float.jl index ec843b4b68faf..716dfa4d8a398 100644 --- a/base/float.jl +++ b/base/float.jl @@ -364,8 +364,10 @@ _round(x::Float32, r::RoundingMode{:Up}) = ceil_llvm(x) _round(x::Float64, r::RoundingMode{:Nearest}) = rint_llvm(x) _round(x::Float32, r::RoundingMode{:Nearest}) = rint_llvm(x) -_round(x::Float16, r::RoundingMode) = Float16(_round(Float32(x), r)) - +_round(x::Float16, r::RoundingMode{:ToZero}) = Float16(_round(Float32(x), r)) +_round(x::Float16, r::RoundingMode{:Down}) = Float16(_round(Float32(x), r)) +_round(x::Float16, r::RoundingMode{:Up}) = Float16(_round(Float32(x), r)) +_round(x::Float16, r::RoundingMode{:Nearest}) = Float16(_round(Float32(x), r)) ## floating point promotions ## promote_rule(::Type{Float32}, ::Type{Float16}) = Float32 From f9337f6e552fc7e24631a2481ea3ea55916fba5c Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Tue, 3 Apr 2018 13:50:16 -0400 Subject: [PATCH 09/18] fix complex --- base/complex.jl | 15 ++++++--------- test/complex.jl | 4 ++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/base/complex.jl b/base/complex.jl index 80ef9edf7e803..f31c3a0c7d32e 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -941,7 +941,9 @@ atanh(z::Complex) = atanh(float(z)) #Rounding complex numbers #Requires two different RoundingModes for the real and imaginary components """ - round(z, RoundingModeReal, RoundingModeImaginary) + round(z::Complex[, RoundingModeReal, [RoundingModeImaginary]]) + round(z::Complex[, RoundingModeReal, [RoundingModeImaginary]]; digits=, base=10) + round(z::Complex[, RoundingModeReal, [RoundingModeImaginary]]; sigdigits=, base=10) Return the nearest integral value of the same type as the complex-valued `z` to `z`, breaking ties using the specified [`RoundingMode`](@ref)s. The first @@ -954,16 +956,11 @@ julia> round(3.14 + 4.5im) 3.0 + 4.0im ``` """ -function round(z::Complex{<:AbstractFloat}, ::RoundingMode{MR}, ::RoundingMode{MI}) where {MR,MI} - Complex(round(real(z), RoundingMode{MR}()), - round(imag(z), RoundingMode{MI}())) +function round(z::Complex, rr::RoundingMode=RoundNearest, ri::RoundingMode=rr; digits=nothing, sigdigits=nothing, base=10) + Complex(round(real(z), rr; digits=digits, sigdigits=sigdigits, base=base), + round(imag(z), ri; digits=digits, sigdigits=sigdigits, base=base)) end -round(z::Complex) = Complex(round(real(z)), round(imag(z))) -function round(z::Complex, digits::Integer; base::Integer = 10) - Complex(round(real(z), digits, base = base), - round(imag(z), digits, base = base)) -end float(z::Complex{<:AbstractFloat}) = z float(z::Complex) = Complex(float(real(z)), float(imag(z))) diff --git a/test/complex.jl b/test/complex.jl index 935e67a7e9de8..6dde71594ff53 100644 --- a/test/complex.jl +++ b/test/complex.jl @@ -893,13 +893,13 @@ end end @testset "round and float, PR #8291" begin - @test round(Complex(1.125, 0.875), 2) == Complex(1.12, 0.88) + @test round(Complex(1.125, 0.875), digits=2) == Complex(1.12, 0.88) @test round(Complex(1.5, 0.5), RoundDown, RoundUp) == Complex(1.0, 1.0) @test round.([1:5;] .+ im) == [1:5;] .+ im @test round.([1:5;] .+ 0.5im) == [1.0:5.0;] @test float(Complex(1, 2)) == Complex(1.0, 2.0) - @test round(float(Complex(π, ℯ)),3) == Complex(3.142, 2.718) + @test round(float(Complex(π, ℯ)), digits=3) == Complex(3.142, 2.718) end @testset "ComplexF16 arithmetic, PR #10003" begin From 793de08d75e4969e1b2789866cc9ce575cd54eba Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Tue, 3 Apr 2018 11:45:21 -0700 Subject: [PATCH 10/18] hopefully fix date warnings --- base/complex.jl | 6 +++--- base/deprecated.jl | 22 +++++++++++----------- base/floatfuncs.jl | 46 +++++++++++++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/base/complex.jl b/base/complex.jl index f31c3a0c7d32e..c547f56e0fbdd 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -956,9 +956,9 @@ julia> round(3.14 + 4.5im) 3.0 + 4.0im ``` """ -function round(z::Complex, rr::RoundingMode=RoundNearest, ri::RoundingMode=rr; digits=nothing, sigdigits=nothing, base=10) - Complex(round(real(z), rr; digits=digits, sigdigits=sigdigits, base=base), - round(imag(z), ri; digits=digits, sigdigits=sigdigits, base=base)) +function round(z::Complex, rr::RoundingMode=RoundNearest, ri::RoundingMode=rr; kwargs...) + Complex(round(real(z), rr; kwargs...) + round(imag(z), ri; kwargs...)) end diff --git a/base/deprecated.jl b/base/deprecated.jl index 2d0bdc5b08897..44e5295d50dd2 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1500,17 +1500,17 @@ end false) # PR 26156 -@deprecate trunc(x, digits) trunc(x; digits=digits) -@deprecate floor(x, digits) floor(x; digits=digits) -@deprecate ceil(x, digits) ceil(x; digits=digits) -@deprecate round(x, digits) round(x; digits=digits) -@deprecate signif(x, digits) round(x; sigdigits=digits, base = base) - -@deprecate trunc(x, digits, base) trunc(x; digits=digits, base = base) -@deprecate floor(x, digits, base) floor(x; digits=digits, base = base) -@deprecate ceil(x, digits, base) ceil(x; digits=digits, base = base) -@deprecate round(x, digits, base) round(x; digits=digits, base = base) -@deprecate signif(x, digits, base) round(x; sigdigits=digits, base = base) +@deprecate trunc(x::Number, digits) trunc(x; digits=digits) +@deprecate floor(x::Number, digits) floor(x; digits=digits) +@deprecate ceil(x::Number, digits) ceil(x; digits=digits) +@deprecate round(x::Number, digits) round(x; digits=digits) +@deprecate signif(x::Number, digits) round(x; sigdigits=digits, base = base) + +@deprecate trunc(x::Number, digits, base) trunc(x; digits=digits, base = base) +@deprecate floor(x::Number, digits, base) floor(x; digits=digits, base = base) +@deprecate ceil(x::Number, digits, base) ceil(x; digits=digits, base = base) +@deprecate round(x::Number, digits, base) round(x; digits=digits, base = base) +@deprecate signif(x::Number, digits, base) round(x; sigdigits=digits, base = base) # issue #25965 @deprecate spawn(cmds::AbstractCmd) run(cmds, wait = false) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index cb6a08eb5ffc1..b4e3b79836ad8 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -121,32 +121,33 @@ round(T::Type, x) round(::Type{T}, x::AbstractFloat, r::RoundingMode{:ToZero}) where {T<:Integer} = trunc(T, x) round(::Type{T}, x::AbstractFloat, r::RoundingMode) where {T<:Integer} = trunc(T, _round(x,r)) -function round(x, r::RoundingMode=RoundNearest; +function round(x::Real, r::RoundingMode=RoundNearest; digits::Union{Nothing,Integer}=nothing, sigdigits::Union{Nothing,Integer}=nothing, base=10) isfinite(x) || return x _round(x,r,digits,sigdigits,base) end -trunc(x; kwargs...) = round(x, RoundToZero; kwargs...) -floor(x; kwargs...) = round(x, RoundDown; kwargs...) -ceil(x; kwargs...) = round(x, RoundUp; kwargs...) +trunc(x::Real; kwargs...) = round(x, RoundToZero; kwargs...) +floor(x::Real; kwargs...) = round(x, RoundDown; kwargs...) +ceil(x::Real; kwargs...) = round(x, RoundUp; kwargs...) _round(x, r::RoundingMode, digits::Nothing, sigdigits::Nothing, base) = _round(x, r) _round(x::Integer, r::RoundingMode) = x -function _round(x, r::RoundingMode, digits::Integer, sigdigits::Nothing, base) - fx = float(x) - if digits >= 0 - sc = oftype(fx, base)^digits - r = round(fx * sc, r) / sc - else - isc = oftype(fx, base)^-digits - r = round(fx / isc, r) * isc +# round x to multiples of 1/invstep +function _round_invstep(x, invstep, r::RoundingMode) + y = _round(x * invstep, r) / invstep + if !isfinite(y) + return x end + return y +end - if !isfinite(r) - if digits > 0 - return fx - elseif x > 0 +# round x to multiples of step +function _round_step(x, step, r::RoundingMode) + # TODO: use div with rounding mode + y = _round(x / step, r) * step + if !isfinite(y) + if x > 0 return (r == RoundUp ? oftype(x, Inf) : zero(fx)) elseif x < 0 return (r == RoundDown ? -oftype(x, Inf) : -zero(fx)) @@ -154,7 +155,18 @@ function _round(x, r::RoundingMode, digits::Integer, sigdigits::Nothing, base) return fx end end - return r + return y +end + +function _round(x, r::RoundingMode, digits::Integer, sigdigits::Nothing, base) + fx = float(x) + if digits >= 0 + invstep = oftype(fx, base)^digits + _round_invstep(fx, invstep, r) + else + step = oftype(fx, base)^-digits + _round_step(fx, step, r) + end end hidigit(x::Integer, base) = ndigits0z(x, base) From 05a4f9b712565820966983442ac8c7a4817238d4 Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Tue, 3 Apr 2018 14:51:44 -0700 Subject: [PATCH 11/18] fix bootstrapping issue --- base/complex.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base/complex.jl b/base/complex.jl index c547f56e0fbdd..f31c3a0c7d32e 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -956,9 +956,9 @@ julia> round(3.14 + 4.5im) 3.0 + 4.0im ``` """ -function round(z::Complex, rr::RoundingMode=RoundNearest, ri::RoundingMode=rr; kwargs...) - Complex(round(real(z), rr; kwargs...) - round(imag(z), ri; kwargs...)) +function round(z::Complex, rr::RoundingMode=RoundNearest, ri::RoundingMode=rr; digits=nothing, sigdigits=nothing, base=10) + Complex(round(real(z), rr; digits=digits, sigdigits=sigdigits, base=base), + round(imag(z), ri; digits=digits, sigdigits=sigdigits, base=base)) end From d073fd3449018ffabf28b7e998e18402040c1297 Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Wed, 4 Apr 2018 10:05:44 -0700 Subject: [PATCH 12/18] tweak docs, fix namedtuple test --- base/floatfuncs.jl | 4 ++-- test/namedtuple.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index b4e3b79836ad8..23c5fb6653359 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -44,8 +44,8 @@ isinteger(x::AbstractFloat) = (x - trunc(x) == 0) """ round([T,] x, [r::RoundingMode]) - round(x, [r::RoundingMode]; digits::Integer= [, base = 10]) - round(x, [r::RoundingMode]; sigdigits::Integer= [, base = 10]) + round(x, [r::RoundingMode]; digits::Integer=0, base = 10) + round(x, [r::RoundingMode]; sigdigits::Integer, base = 10) Rounds the number `x`. diff --git a/test/namedtuple.jl b/test/namedtuple.jl index a97591ee9a290..9f09e28ab30bd 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -72,7 +72,7 @@ end @test map(+, (x=1, y=2), (x=10, y=20)) == (x=11, y=22) @test_throws ArgumentError map(+, (x=1, y=2), (y=10, x=20)) @test map(string, (x=1, y=2)) == (x="1", y="2") -@test map(round, (x=1//3, y=Int), (x=3, y=2//3)) == (x=0.333, y=1) +@test map(round, (x=UInt, y=Int), (x=3.1, y=2//3)) == (x=UInt(3), y=1) @test merge((a=1, b=2), (a=10,)) == (a=10, b=2) @test merge((a=1, b=2), (a=10, z=20)) == (a=10, b=2, z=20) From 2418c85ecfcf3fff48ef34923e66db94ae61bfae Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Wed, 4 Apr 2018 10:08:07 -0700 Subject: [PATCH 13/18] fix typo --- base/floatfuncs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 23c5fb6653359..8b90a7ba0664a 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -53,7 +53,7 @@ Without keyword arguments, `x` is rounded to an integer value, returning a value `T`, or of the same type of `x` if no `T` is provided. An [`InexactError`](@ref) will be thrown if the value is not representable by `T`, similar to [`convert`](@ref). -If the `digits` keyword argument is provied, it rounds to the specified number of digits +If the `digits` keyword argument is provided, it rounds to the specified number of digits after the decimal place (or before if negative), in base `base`. If the `sigdigits` keyword argument is provided, it rounds to the specified number of From a89385f810f1e13cea844f7cd7a9c0a4c4f5579e Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Wed, 4 Apr 2018 11:40:47 -0700 Subject: [PATCH 14/18] fix a few more errors --- base/floatfuncs.jl | 6 +++--- test/subtype.jl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 8b90a7ba0664a..7a15934ed58a3 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -148,11 +148,11 @@ function _round_step(x, step, r::RoundingMode) y = _round(x / step, r) * step if !isfinite(y) if x > 0 - return (r == RoundUp ? oftype(x, Inf) : zero(fx)) + return (r == RoundUp ? oftype(x, Inf) : zero(x)) elseif x < 0 - return (r == RoundDown ? -oftype(x, Inf) : -zero(fx)) + return (r == RoundDown ? -oftype(x, Inf) : -zero(x)) else - return fx + return x end end return y diff --git a/test/subtype.jl b/test/subtype.jl index 69150ee6fb34c..5e68998d34e33 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -1253,7 +1253,7 @@ for it = 1:5 global x_24305 = x_24305 + h end -@test round.(x_24305, 2) == [1.78, 1.42, 1.24] +@test round.(x_24305, digits=2) == [1.78, 1.42, 1.24] # PR #24399 let (t, e) = intersection_env(Tuple{Union{Int,Int8}}, Tuple{T} where T) From d054dfc473ccc637f58d26645985b6689e74e863 Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Wed, 4 Apr 2018 14:47:06 -0700 Subject: [PATCH 15/18] remove troublesome precompile --- stdlib/Pkg3/src/precompile.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/Pkg3/src/precompile.jl b/stdlib/Pkg3/src/precompile.jl index e20ee5d367ea2..5d7d6ad1fbae5 100644 --- a/stdlib/Pkg3/src/precompile.jl +++ b/stdlib/Pkg3/src/precompile.jl @@ -544,7 +544,6 @@ precompile(Tuple{typeof(Base.replace_ref_end_!), Int64, Nothing}) precompile(Tuple{typeof(Base.replace_ref_end_!), LineNumberNode, Nothing}) precompile(Tuple{typeof(Base.repr), String}) precompile(Tuple{typeof(Base.reverseind), String, Int64}) -precompile(Tuple{typeof(Base.round), Float64, Int64}) precompile(Tuple{typeof(Base.round), Type{Int64}, Float64}) precompile(Tuple{typeof(Base.run), Base.Cmd, Tuple{Base.DevNullStream, Base.DevNullStream, Base.DevNullStream}}) precompile(Tuple{typeof(Base.setindex!), Array{Array{Base.BitArray{2}, 1}, 1}, Array{Any, 1}, Int64}) From baedebb982ad67077679df54b8074aa5d146d9af Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Wed, 4 Apr 2018 14:48:32 -0700 Subject: [PATCH 16/18] fix round call --- stdlib/Pkg3/test/repl.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Pkg3/test/repl.jl b/stdlib/Pkg3/test/repl.jl index 70d4a25fa3922..43d43f39a53e9 100644 --- a/stdlib/Pkg3/test/repl.jl +++ b/stdlib/Pkg3/test/repl.jl @@ -8,7 +8,7 @@ import LibGit2 include("utils.jl") -const TEST_SIG = LibGit2.Signature("TEST", "TEST@TEST.COM", round(time(), 0), 0) +const TEST_SIG = LibGit2.Signature("TEST", "TEST@TEST.COM", round(time()), 0) const TEST_PKG = (name = "Example", uuid = UUID("7876af07-990d-54b4-ab0e-23690620f79a")) function git_init_package(tmp, path) From 03ed3fa7bc38372b60b9986a323d3530addd4494 Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Wed, 4 Apr 2018 14:50:02 -0700 Subject: [PATCH 17/18] more fixes --- stdlib/Pkg/test/pkg.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/Pkg/test/pkg.jl b/stdlib/Pkg/test/pkg.jl index 5e2ea64e63abc..357580dad23af 100644 --- a/stdlib/Pkg/test/pkg.jl +++ b/stdlib/Pkg/test/pkg.jl @@ -151,7 +151,7 @@ temp_pkg_dir() do end LibGit2.with(LibGit2.GitRepo, Pkg.dir("Example3")) do repo LibGit2.add!(repo, "README.md") - test_sig = LibGit2.Signature("TEST", "TEST@TEST.COM", round(time(), 0), 0) + test_sig = LibGit2.Signature("TEST", "TEST@TEST.COM", round(time()), 0) LibGit2.commit(repo, "testmsg"; author=test_sig, committer=test_sig) end @@ -182,7 +182,7 @@ temp_pkg_dir() do test_commit = LibGit2.with(LibGit2.GitRepo, Pkg.dir("Example")) do repo LibGit2.add!(repo, "README.md") - test_sig = LibGit2.Signature("TEST", "TEST@TEST.COM", round(time(), 0), 0) + test_sig = LibGit2.Signature("TEST", "TEST@TEST.COM", round(time()), 0) LibGit2.commit(repo, "testmsg"; author=test_sig, committer=test_sig) end Pkg.checkout("Example") From a6dd6a4dacd5b9a2169d86e41f11bf290e11d73c Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Thu, 5 Apr 2018 13:31:29 -0700 Subject: [PATCH 18/18] add NEWS item --- NEWS.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 4a52f28173a83..3a396acd85a3c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -634,8 +634,9 @@ Library improvements * `IOBuffer` can take the `sizehint` keyword argument to suggest a capacity of the buffer ([#25944]). - * `trunc`, `floor`, `ceil`, `round`, and `signif` specify `base` using a - keyword argument. ([#26156]) + * `trunc`, `floor`, `ceil`, and `round` specify `digits`, `sigdigits` and `base` using + keyword arguments. ([#26156], [#26670]) + Compiler/Runtime improvements ----------------------------- @@ -1134,6 +1135,8 @@ Deprecated or removed * `isupper`, `islower`, `ucfirst` and `lcfirst` have been deprecated in favor of `isuppercase`, `islowercase`, `uppercasefirst` and `lowercasefirst`, respectively ([#26442]). + * `signif` has been deprecated in favor of the `sigdigits` keyword argument to `round`. + Command-line option changes --------------------------- @@ -1442,4 +1445,5 @@ Command-line option changes [#26286]: https://github.com/JuliaLang/julia/issues/26286 [#26436]: https://github.com/JuliaLang/julia/issues/26436 [#26442]: https://github.com/JuliaLang/julia/issues/26442 -[#26600]: https://github.com/JuliaLang/julia/issues/26600 \ No newline at end of file +[#26600]: https://github.com/JuliaLang/julia/issues/26600 +[#26670]: https://github.com/JuliaLang/julia/issues/26670 \ No newline at end of file