Serializing or representing BigFloats is tricky because: a. the BigFloat structure uses pointers, and b. the pointed to buffer is controlled by the GMP library which is an external library wrapped in Julia.
So as a first step, here are some functions to textually format a BigFloat in an accurate and easy to manipulate way:
# numbits(a) returns the number of significant digits in a BigFloat
# including digits both left and right of floating point.
# For example:
# julia> numbits(BigFloat(3/8)
# 2
#
# This is the trickiest function since it looks slightly into
# the internal representation in GMP of BigInt data.
function numbits(a::BigFloat)
n = a.prec
for i=1:(a.prec>>count_ones(sizeof(Base.GMP.Limb)*8-1))
tz = trailing_zeros(unsafe_load(a.d,i))
n -= tz
if tz < sizeof(Base.GMP.Limb)*8
break
end
end
return n
end
# mantissarep(a) returns a tuple with two elements. The first element is a BigInt
# holding all the significant bits of a BigFloat, and the second holds
# the exponent needed to return the floating point to its position.
# Thus, as an example, the following holds:
# julia> a = BigFloat(1.1)
# 1.100000000000000088817841...
#
# julia> mantissarep(a)
# (2476979795053773, 51)
#
# julia> big"2476979795053773"/big"2"^51 == a
# true
#
mantissarep(a::BigFloat) = (BigInt(a*BigFloat(2)^(numbits(a)-a.exp)),
numbits(a)-a.exp)
# bigfloattext(a) returns an easy textual representation of a BigFloat
function bigfloattext(bf::BigFloat)
(a,b) = mantissarep(bf)
return "$(sign(a)==-1 ? "-" : "")big\"$(dec(abs(a)))\"/big\"2\"^$(b)"
end
# bigfloatbintext(a) returns an easy binary textual representation a BigFloat
function bigfloatbintext(bf::BigFloat)
(a,b) = mantissarep(bf)
return "$(sign(a)==-1 ? "-" : "")big\"0b$(bin(abs(a)))\"/big\"2\"^0b$(bin(b))"
end
With these functions, one method of serializing a BigFloat is simply to write the string output of bigfloattext. This method is not very compact, but it will be easy to deserialize (the parse method for BigFloats could be used) and relatively clear. To make a more compact serialization, the bytes of mantissarep together with the precision field of the BigFloat could be written. This would make this answer a bit longer, so I will add if requested.
For example, writing:
julia> a = sin(BigFloat(π)/3) # calculate some BigFloat
8.660254037844386467637231707529361834714026269051903140279034897259665084543988e-01
julia> println(bigfloattext(a)) # represent it as a string
big"100278890836790510567389408543623384672710501789331344711007167057270294106993"/big"2"^256
julia> # show representation is faithful
julia> big"100278890836790510567389408543623384672710501789331344711007167057270294106993"/big"2"^256 == a
true
Note that (in regard to other answer) writing the d field (=data field) of a BigFloat which is a Ptr{Limb} type is rather useless and could possibly lead to memory corruption.
UPDATE: Guided by the poster's comment below, here are another couple of functions to convert a BigFloat into a byte representation:
function BigFloat2Bytes(bf::BigFloat)
bf2 = bf/big"2"^exponent(bf)-1.0
bvec = Vector{UInt8}()
push!(bvec,0x01)
while bf2 != 0.0
bf2 *= 256
b = trunc(Int, bf2)
push!(bvec, UInt8(b))
bf2 -= b
end
return (bvec, exponent(bf))
end
function Bytes2BigFloat(bvec, e)
bf = zero(BigInt)
for b in bvec
bf = bf*256 + b
end
return BigFloat(bf*BigFloat(2)^(e-8*length(bvec)+8))
end
With these we have:
julia> a = BigFloat(123.2323)
1.23232299999999995065991242881...e+02
julia> BigFloat2Bytes(a)
(UInt8[0x01, 0xec, 0xed, 0xe0, 0x0d, 0x1b, 0x71, 0x70], 6)
julia> Bytes2BigFloat(BigFloat2Bytes(a)...)
1.23232299999999995065991242881...e+02
julia> Bytes2BigFloat(BigFloat2Bytes(a)...) == a
true