1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
|
# This file is a part of Julia. License is MIT: https://julialang.org/license
module Rounding
let fenv_consts = Vector{Cint}(undef, 9)
ccall(:jl_get_fenv_consts, Cvoid, (Ptr{Cint},), fenv_consts)
global const JL_FE_INEXACT = fenv_consts[1]
global const JL_FE_UNDERFLOW = fenv_consts[2]
global const JL_FE_OVERFLOW = fenv_consts[3]
global const JL_FE_DIVBYZERO = fenv_consts[4]
global const JL_FE_INVALID = fenv_consts[5]
global const JL_FE_TONEAREST = fenv_consts[6]
global const JL_FE_UPWARD = fenv_consts[7]
global const JL_FE_DOWNWARD = fenv_consts[8]
global const JL_FE_TOWARDZERO = fenv_consts[9]
end
export
RoundingMode, RoundNearest, RoundToZero, RoundUp, RoundDown, RoundFromZero,
RoundNearestTiesAway, RoundNearestTiesUp,
rounding, setrounding,
get_zero_subnormals, set_zero_subnormals
## rounding modes ##
"""
RoundingMode
A type used for controlling the rounding mode of floating point operations (via
[`rounding`](@ref)/[`setrounding`](@ref) functions), or as
optional arguments for rounding to the nearest integer (via the [`round`](@ref)
function).
Currently supported rounding modes are:
- [`RoundNearest`](@ref) (default)
- [`RoundNearestTiesAway`](@ref)
- [`RoundNearestTiesUp`](@ref)
- [`RoundToZero`](@ref)
- [`RoundFromZero`](@ref) ([`BigFloat`](@ref) only)
- [`RoundUp`](@ref)
- [`RoundDown`](@ref)
"""
struct RoundingMode{T} end
"""
RoundNearest
The default rounding mode. Rounds to the nearest integer, with ties (fractional values of
0.5) being rounded to the nearest even integer.
"""
const RoundNearest = RoundingMode{:Nearest}()
"""
RoundToZero
[`round`](@ref) using this rounding mode is an alias for [`trunc`](@ref).
"""
const RoundToZero = RoundingMode{:ToZero}()
"""
RoundUp
[`round`](@ref) using this rounding mode is an alias for [`ceil`](@ref).
"""
const RoundUp = RoundingMode{:Up}()
"""
RoundDown
[`round`](@ref) using this rounding mode is an alias for [`floor`](@ref).
"""
const RoundDown = RoundingMode{:Down}()
"""
RoundFromZero
Rounds away from zero.
This rounding mode may only be used with `T == BigFloat` inputs to [`round`](@ref).
# Examples
```jldoctest
julia> BigFloat("1.0000000000000001", 5, RoundFromZero)
1.06
```
"""
const RoundFromZero = RoundingMode{:FromZero}() # mpfr only
"""
RoundNearestTiesAway
Rounds to nearest integer, with ties rounded away from zero (C/C++
[`round`](@ref) behaviour).
"""
const RoundNearestTiesAway = RoundingMode{:NearestTiesAway}()
"""
RoundNearestTiesUp
Rounds to nearest integer, with ties rounded toward positive infinity (Java/JavaScript
[`round`](@ref) behaviour).
"""
const RoundNearestTiesUp = RoundingMode{:NearestTiesUp}()
to_fenv(::RoundingMode{:Nearest}) = JL_FE_TONEAREST
to_fenv(::RoundingMode{:ToZero}) = JL_FE_TOWARDZERO
to_fenv(::RoundingMode{:Up}) = JL_FE_UPWARD
to_fenv(::RoundingMode{:Down}) = JL_FE_DOWNWARD
function from_fenv(r::Integer)
if r == JL_FE_TONEAREST
return RoundNearest
elseif r == JL_FE_DOWNWARD
return RoundDown
elseif r == JL_FE_UPWARD
return RoundUp
elseif r == JL_FE_TOWARDZERO
return RoundToZero
else
throw(ArgumentError("invalid rounding mode code: $r"))
end
end
"""
setrounding(T, mode)
Set the rounding mode of floating point type `T`, controlling the rounding of basic
arithmetic functions ([`+`](@ref), [`-`](@ref), [`*`](@ref),
[`/`](@ref) and [`sqrt`](@ref)) and type conversion. Other numerical
functions may give incorrect or invalid values when using rounding modes other than the
default [`RoundNearest`](@ref).
Note that this is currently only supported for `T == BigFloat`.
"""
setrounding(T::Type, mode)
"""
rounding(T)
Get the current floating point rounding mode for type `T`, controlling the rounding of basic
arithmetic functions ([`+`](@ref), [`-`](@ref), [`*`](@ref), [`/`](@ref)
and [`sqrt`](@ref)) and type conversion.
See [`RoundingMode`](@ref) for available modes.
"""
:rounding
setrounding_raw(::Type{<:Union{Float32,Float64}}, i::Integer) = ccall(:fesetround, Int32, (Int32,), i)
rounding_raw(::Type{<:Union{Float32,Float64}}) = ccall(:fegetround, Int32, ())
rounding(::Type{T}) where {T<:Union{Float32,Float64}} = from_fenv(rounding_raw(T))
"""
setrounding(f::Function, T, mode)
Change the rounding mode of floating point type `T` for the duration of `f`. It is logically
equivalent to:
old = rounding(T)
setrounding(T, mode)
f()
setrounding(T, old)
See [`RoundingMode`](@ref) for available rounding modes.
"""
function setrounding(f::Function, ::Type{T}, rounding::RoundingMode) where T
old_rounding_raw = rounding_raw(T)
setrounding(T,rounding)
try
return f()
finally
setrounding_raw(T,old_rounding_raw)
end
end
# Should be equivalent to:
# setrounding(Float64,r) do
# convert(T,x)
# end
# but explicit checks are currently quicker (~20x).
# Assumes conversion is performed by rounding to nearest value.
# To avoid ambiguous dispatch with methods in mpfr.jl:
(::Type{T})(x::Real, r::RoundingMode) where {T<:AbstractFloat} = _convert_rounding(T,x,r)
_convert_rounding(::Type{T}, x::Real, r::RoundingMode{:Nearest}) where {T<:AbstractFloat} = convert(T,x)
function _convert_rounding(::Type{T}, x::Real, r::RoundingMode{:Down}) where T<:AbstractFloat
y = convert(T,x)
y > x ? prevfloat(y) : y
end
function _convert_rounding(::Type{T}, x::Real, r::RoundingMode{:Up}) where T<:AbstractFloat
y = convert(T,x)
y < x ? nextfloat(y) : y
end
function _convert_rounding(::Type{T}, x::Real, r::RoundingMode{:ToZero}) where T<:AbstractFloat
y = convert(T,x)
if x > 0.0
y > x ? prevfloat(y) : y
else
y < x ? nextfloat(y) : y
end
end
"""
set_zero_subnormals(yes::Bool) -> Bool
If `yes` is `false`, subsequent floating-point operations follow rules for IEEE arithmetic
on subnormal values ("denormals"). Otherwise, floating-point operations are permitted (but
not required) to convert subnormal inputs or outputs to zero. Returns `true` unless
`yes==true` but the hardware does not support zeroing of subnormal numbers.
`set_zero_subnormals(true)` can speed up some computations on some hardware. However, it can
break identities such as `(x-y==0) == (x==y)`.
"""
set_zero_subnormals(yes::Bool) = ccall(:jl_set_zero_subnormals,Int32,(Int8,),yes)==0
"""
get_zero_subnormals() -> Bool
Return `false` if operations on subnormal floating-point values ("denormals") obey rules
for IEEE arithmetic, and `true` if they might be converted to zeros.
"""
get_zero_subnormals() = ccall(:jl_get_zero_subnormals,Int32,())!=0
end #module
|