Permalink
Browse files

add BitsFloat abstract type, leverage dispatch for rounding modes

  • Loading branch information...
1 parent 43d9445 commit e77e7eb22fdcadb56a3428b61f2a85380fb369d7 @simonbyrne simonbyrne committed Dec 1, 2013
Showing with 48 additions and 60 deletions.
  1. +5 −1 NEWS.md
  2. +8 −0 base/deprecated.jl
  3. +0 −3 base/exports.jl
  4. +4 −17 base/mpfr.jl
  5. +6 −6 base/rounding.jl
  6. +3 −3 doc/manual/integers-and-floating-point-numbers.rst
  7. +13 −21 doc/stdlib/base.rst
  8. +3 −3 test/mpfr.jl
  9. +6 −6 test/rounding.jl
View
@@ -49,14 +49,18 @@ Deprecated or removed
* The `Stat` type is renamed `StatStruct` ([#4670])
+ * `set_rounding`, `get_rounding` and `with_rounding` now take an additional
+ argument specifying the floating point type to which they apply. The old
+ behaviour and `[get/set/with]_bigfloat_rounding` functions are deprecated ([#5007])
+
[#4775]: https://github.com/JuliaLang/julia/issues/4775
[#4870]: https://github.com/JuliaLang/julia/issues/4870
[#4766]: https://github.com/JuliaLang/julia/issues/4766
[#4782]: https://github.com/JuliaLang/julia/issues/4782
[#4759]: https://github.com/JuliaLang/julia/issues/4759
[#4819]: https://github.com/JuliaLang/julia/issues/4819
[#4670]: https://github.com/JuliaLang/julia/issues/4670
-
+[#5007]: https://github.com/JuliaLang/julia/issues/5007
Julia v0.2.0 Release Notes
View
@@ -359,5 +359,13 @@ const Stat = StatStruct
export CharString
const CharString = UTF32String
+@deprecate set_rounding(r::RoundingMode) set_rounding(Float64,r)
+@deprecate get_rounding() get_rounding(Float64)
+@deprecate with_rounding(f::Function, r::RoundingMode) with_rounding(f::Function, Float64, r)
+
+@deprecate set_bigfloat_rounding(r::RoundingMode) set_rounding(BigFloat,r)
+@deprecate get_bigfloat_rounding() get_rounding(BigFloat)
+@deprecate with_bigfloat_rounding(f::Function, r::RoundingMode) with_rounding(f::Function, BigFloat, r)
+
# 0.3 discontinued functions
View
@@ -842,9 +842,6 @@ export
get_bigfloat_precision,
set_bigfloat_precision,
with_bigfloat_precision,
- get_bigfloat_rounding,
- set_bigfloat_rounding,
- with_bigfloat_rounding,
get_rounding,
set_rounding,
with_rounding,
View
@@ -4,10 +4,7 @@ export
BigFloat,
get_bigfloat_precision,
set_bigfloat_precision,
- with_bigfloat_precision,
- set_bigfloat_rounding,
- get_bigfloat_rounding,
- with_bigfloat_rounding
+ with_bigfloat_precision
import
Base: (*), +, -, /, <, <=, ==, >, >=, ^, besselj, besselj0, besselj1, bessely,
@@ -20,7 +17,7 @@ import
itrunc, eps, signbit, sin, cos, tan, sec, csc, cot, acos, asin, atan,
cosh, sinh, tanh, sech, csch, coth, acosh, asinh, atanh, atan2,
serialize, deserialize, inf, nan, hash, cbrt, typemax, typemin,
- realmin, realmax
+ realmin, realmax, get_rounding, set_rounding
import Base.Math.lgamma_r
@@ -615,8 +612,8 @@ function from_mpfr(c::Integer)
RoundingMode(c)
end
-get_bigfloat_rounding() = from_mpfr(ROUNDING_MODE[end])
-set_bigfloat_rounding(r::RoundingMode) = ROUNDING_MODE[end] = to_mpfr(r)
+get_rounding(::Type{BigFloat}) = from_mpfr(ROUNDING_MODE[end])
+set_rounding(::Type{BigFloat},r::RoundingMode) = ROUNDING_MODE[end] = to_mpfr(r)
function copysign(x::BigFloat, y::BigFloat)
z = BigFloat()
@@ -701,16 +698,6 @@ function with_bigfloat_precision(f::Function, precision::Integer)
end
end
-function with_bigfloat_rounding(f::Function, rounding::RoundingMode)
- old_rounding = get_bigfloat_rounding()
- set_bigfloat_rounding(rounding)
- try
- return f()
- finally
- set_bigfloat_rounding(old_rounding)
- end
-end
-
function string(x::BigFloat)
lng = 128
for i = 1:2
View
@@ -46,16 +46,16 @@ function from_fenv(r::Integer)
end
end
-set_rounding(r::RoundingMode) = ccall(:fesetround, Cint, (Cint,), to_fenv(r))
-get_rounding() = from_fenv(ccall(:fegetround, Cint, ()))
+set_rounding{T<:Union(Float32,Float64)}(::Type{T},r::RoundingMode) = ccall(:fesetround, Cint, (Cint,), to_fenv(r))
+get_rounding{T<:Union(Float32,Float64)}(::Type{T}) = from_fenv(ccall(:fegetround, Cint, ()))
-function with_rounding(f::Function, rounding::RoundingMode)
- old_rounding = get_rounding()
- set_rounding(rounding)
+function with_rounding{T}(f::Function, ::Type{T}, rounding::RoundingMode)
+ old_rounding = get_rounding(T)
+ set_rounding(T,rounding)
try
return f()
finally
- set_rounding(old_rounding)
+ set_rounding(T,old_rounding)
end
end
@@ -500,7 +500,7 @@ presented in the `IEEE 754 standard <http://en.wikipedia.org/wiki/IEEE_754-2008>
julia> 1.1 + 0.1
1.2000000000000002
- julia> with_rounding(RoundDown) do
+ julia> with_rounding(Float64,RoundDown) do
1.1 + 0.1
end
1.2
@@ -603,12 +603,12 @@ will take these changes in account:
.. doctest::
- julia> with_bigfloat_rounding(RoundUp) do
+ julia> with_rounding(BigFloat,RoundUp) do
BigFloat(1) + BigFloat("0.1")
end
1.100000000000000000000000000000000000000000000000000000000000000000000000000003e+00 with 256 bits of precision
- julia> with_bigfloat_rounding(RoundDown) do
+ julia> with_rounding(BigFloat,RoundDown) do
BigFloat(1) + BigFloat("0.1")
end
1.099999999999999999999999999999999999999999999999999999999999999999999999999986e+00 with 256 bits of precision
View
@@ -3135,22 +3135,26 @@ Numbers
``BigFloat(2.1)`` may not yield what you expect. You may prefer to
initialize constants using strings, e.g., ``BigFloat("2.1")``.
-.. function:: get_rounding()
+.. function:: get_rounding(T)
- Get the current floating point rounding mode. Valid modes are ``RoundNearest``, ``RoundToZero``, ``RoundUp`` and ``RoundDown``.
+ Get the current floating point rounding mode for type ``T``. Valid modes
+ are ``RoundNearest``, ``RoundToZero``, ``RoundUp``, ``RoundDown``, and
+ ``RoundFromZero`` (``BigFloat`` only).
-.. function:: set_rounding(mode)
+.. function:: set_rounding(T, mode)
- Set the floating point rounding mode. See ``get_rounding`` for available modes
+ Set the rounding mode of floating point type ``T``. Note that this may
+ affect other types, for instance changing the rounding mode of ``Float64``
+ will change the rounding mode of ``Float32``. See ``get_rounding`` for available modes
-.. function:: with_rounding(f::Function,mode)
+.. function:: with_rounding(f::Function, T, mode)
- Change the floating point rounding mode for the duration of ``f``. It is logically equivalent to::
+ Change the rounding mode of floating point type ``T`` for the duration of ``f``. It is logically equivalent to::
- old = get_rounding()
- set_rounding(mode)
+ old = get_rounding(T)
+ set_rounding(T, mode)
f()
- set_rounding(old)
+ set_rounding(T, old)
See ``get_rounding`` for available rounding modes.
@@ -3240,18 +3244,6 @@ The `BigFloat` type implements arbitrary-precision floating-point aritmetic usin
f()
set_bigfloat_precision(old)
-.. function:: get_bigfloat_rounding()
-
- Get the current BigFloat rounding mode. Valid modes are ``RoundNearest``, ``RoundToZero``, ``RoundUp``, ``RoundDown``, ``RoundFromZero``
-
-.. function:: set_bigfloat_rounding(mode)
-
- Set the BigFloat rounding mode. See get_bigfloat_rounding for available modes
-
-.. function:: with_bigfloat_rounding(f::Function,mode)
-
- Change the BigFloat rounding mode for the duration of ``f``. See ``get_bigfloat_rounding`` for available rounding modes; see also ``with_bigfloat_precision``.
-
Random Numbers
--------------
View
@@ -82,14 +82,14 @@ z = BigFloat(30)
# rounding modes
with_bigfloat_precision(4) do
# default mode is round to nearest
- down, up = with_bigfloat_rounding(RoundNearest) do
+ down, up = with_rounding(BigFloat,RoundNearest) do
BigFloat("0.0938"), BigFloat("0.102")
end
- with_bigfloat_rounding(RoundDown) do
+ with_rounding(BigFloat,RoundDown) do
@test BigFloat(0.1) == down
@test BigFloat(0.1) != up
end
- with_bigfloat_rounding(RoundUp) do
+ with_rounding(BigFloat,RoundUp) do
@test BigFloat(0.1) != down
@test BigFloat(0.1) == up
end
View
@@ -16,7 +16,7 @@ d = prevfloat(1.)
@test b - a === c
# RoundToZero
-with_rounding(RoundToZero) do
+with_rounding(Float64,RoundToZero) do
@test a + b === d
@test - a - b === -d
@test a - b === -c
@@ -30,15 +30,15 @@ end
@test b - a == c
# RoundUp
-with_rounding(RoundUp) do
+with_rounding(Float64,RoundUp) do
@test a + b === 1.
@test - a - b === -d
@test a - b === -c
@test b - a === c
end
# RoundDown
-with_rounding(RoundDown) do
+with_rounding(Float64,RoundDown) do
@test a + b === d
@test - a - b === -1.
@test a - b === -c
@@ -59,7 +59,7 @@ d32 = prevfloat(1.0f0)
@test b32 - a32 === c32
# RoundToZero
-with_rounding(RoundToZero) do
+with_rounding(Float32,RoundToZero) do
@test a32 + b32 === d32
@test - a32 - b32 === -d32
@test a32 - b32 === -c32
@@ -73,15 +73,15 @@ end
@test b32 - a32 == c32
# RoundUp
-with_rounding(RoundUp) do
+with_rounding(Float32,RoundUp) do
@test a32 + b32 === 1.0f0
@test - a32 - b32 === -d32
@test a32 - b32 === -c32
@test b32 - a32 === c32
end
# RoundDown
-with_rounding(RoundDown) do
+with_rounding(Float32,RoundDown) do
@test a32 + b32 === d32
@test - a32 - b32 === -1.0f0
@test a32 - b32 === -c32

6 comments on commit e77e7eb

This is a very nice API.

So why is it deprecated to call with_rounding without a type? That should set the rounding modes for all floating-point types. Of course it should fail when the rounding mode isn't supported by all types – i.e. RoundFromZero – but for rounding modes that are universally supported (the rest of them), it should just work.

Owner

JeffBezanson replied Feb 13, 2014

That's a fair point, but the reason for the deprecation is probably that "all floating-point types" is not well-defined. New types can add methods to with_rounding, but it seems we'd need some other mechanism to extend the behavior of with_rounding without a type.

This would require floating-point types registering themselves to support rounding mode changes. This is unavoidable with an API like this that involves global state.

Contributor

simonbyrne replied Feb 14, 2014

Yep, that's exactly the reason why I deprecated it, as I couldn't figure out a neat way to do hooks (I haven't come across them anywhere else in Base). In the end, I couldn't really think of a good use case for when you would want to change both modes, since you can always call set_rounding(typeof(x),RoundDown), or exploit parametric types at dispatch. Also it forces people to think about the types they're using, which is probably a good thing if you're mucking about with rounding modes.

I can think of a situation: when I'm demoing stuff ;-). But seriously, I feel like this really undermines the genericness of this feature. The idea is that I can switch this and know that all the intervening computations have the rounding mode I just set, regardless of type. That is exactly what you need for the best use case for this, which is Kahan's approach to testing numerical stability: run your program in each rounding mode and see if you get similar results. If you have to go around and nitpick with the rounding mode of each type, then this isn't very helpful.

Please sign in to comment.