Working on double-double math, I found this to be a problem. It makes 
validating high precision numerics more difficult than it should be.  The 
example illustrates what is going on.

#=
 parse(Float64,string(BigFloat)) is less accurate than it should be
 at least in this case BigFloat is the result of BigFloat addition
=#
Base.ldexp(signif::Integer, pow2::Integer) = ldexp(signif+zero(Float64), 
pow2);
set_bigfloat_precision(ceil(Int,112*log(10)/log(2)));
piStr = string(
  "3.141592653589793238462643383279502884197169399375105820",
  "9749445923078164062862089986280348253421170679821480865132" );
piBig = parse(BigFloat,piStr);
piStr == string(piBig) # true

# the double-double value nearest Pi
nearpi_qhi = 884279719003555//281474976710656;
nearpi_qlo = 4967757600021511//40564819207303340847894502572032;
nearpi_hi = ldexp(num(nearpi_qhi),-round(Int,log2(den(nearpi_qhi))));
nearpi_lo = ldexp(num(nearpi_qlo),-round(Int,log2(den(nearpi_qlo))));

nearpi_q = nearpi_qhi + nearpi_qlo;
nearpi_num = num(nearpi_q);
nearpi_pow2 = -round(Int,log2(den(nearpi_q)));
ldexp(nearpi_num,nearpi_pow2) == nearpi_hi # true

nearpiBig = ldexp(parse(BigFloat,string(nearpi_num)),nearpi_pow2);
#  3.14159265358979..187500000000

abserr=abs(piBig-nearpiBig);
relerr=abserr/piBig;
abserr, relerr # ~(2.995-33,9.533-34)

# replacing nearpi_lo with nextfloat(_) or prevfloat(_)
# makes the abserr and relerr values more coarse
# ∴ these values are the best Float64x2 approximation

parse_recover_nearpi  =  parse(BigFloat,string(nearpi_hi)) +
                         parse(BigFloat,string(nearpi_lo));
coerce_recover_nearpi =  BigFloat(nearpi_hi) + BigFloat(nearpi_lo);
parse_recover_nearpi  == nearpiBig # false
coerce_recover_nearpi == nearpiBig # true

#=
  numerical interconversion antisymmetry is unhelpful
  ---------------------------------------------------
  better value obtains with parse(BigFloat,string(Float64))
  better value obtains with Float64(value(BigFloat))
         and not with parse(Float64,string(BigFloat))
=#

Reply via email to