Truncating BigFloat

During computing, I need to truncate some BigFloat results (still to BigFloat, just with less precision) to save memory. Is there a way to truncate BigFloat without changing the global precision?

You can truncate (or use e.g. round):

julia> big"1"/3
0.3333333333333333333333333333333333333333333333333333333333333333333333333333348

julia> trunc(big"1"/3, digits=30)
0.3333333333333333333333333333330000000000000000000000000000000000000000000000018

likely not what you want because the "18" in the end, but it would be the closes approximation, unless you do in base 2 (or 4, 8...), something like:

julia> round(big"1"/3, digits=30, base=2)
0.333333333022892475128173828125

Note, none of this changes the storage requirements. These all take same space, just showing shorter in decimal expansion.

You can also do:
julia> b = big"1"/3
0.3333333333333333333333333333333333333333333333333333333333333333333333333333348

old = precision(BigFloat)
setprecision(BigFloat, 30)

julia> b  # apparently doesn't change already defined variables:
0.3333333333333333333333333333333333333333333333333333333333333333333333333333348

julia> b = round(big"1"/3, digits=30, base=2)
0.33333333395

julia> setprecision(BigFloat, old)

julia> b # note I changed it, otherwise would have gotten old value, and future calculations will be at the old 256 bit default:
0.33333333395

I though something like this should work temporarily, doing same as above, as from the docs, but unsure why not:

julia> setprecision(BigFloat, 30) do big"1" end
ERROR: syntax: "Base.GMP.BigInt(alloc=2, size=1, d=0x0000000004916ec0)" is not a valid function argument name around REPL[84]:1

I would be concerned about changing the global setting (locally) if you have many threads. It’s not mentioned in the docs, but most likely would affect all, for wanted, or unwanted…, effect.

What you might want to do is rather use ArbFloats.jl. It’s faster and defaults to fewer digits, and has more features. You could also use it with BigFloats, i.e. for your thing cast to its type and it would have its shorter default, not messing with BigFloat’s. Both defaults are settable.

One other way that might be better for you are Rationals. Of e.g. two Int64 takes only 128 bits in total, still plausible would overflow. Or of BigInts, would never overflow, and potentially take less memory than for one BigFloat(?).

1 Like

Just pass the precision parameter to the BigFloat constructor:

julia> x = big(pi)
3.141592653589793238462643383279502884197169399375105820974944592307816406286198

julia> BigFloat(x, precision=10) # store rounded value in 10-bit precision
3.1406
4 Likes

I didn’t realize this, note two things however, this is base-2 significant digits, why

julia> BigFloat(x, precision=11)  # actually also correct, assuming you realize the base, and limited, but looks odd...:
3.1406

julia> x = BigFloat(x, precision=12)
3.1416

julia> x*x  # but also further calculations would add bits, e.g. * doubles them, so no longer limited by 12 (nor limiting storage, still at 256):
9.86966037750244140625

One general note is that if you are doing lots of things with different precison, you probably should be using the Arb library rather than the builtin BigFloat.

1 Like

one further question: how do I copy an array, changing the precision? Using broadcast would result in allocation:

A[1,:] = BigFloat.(B[1,:], precision=10)

You can use .= to write into a pre-allocated array like A[1,:]. (Be sure to use @views if you want to avoid allocation with B[1,:].) Of course, creating new BigFloat values will allocate anyway, since BigFloat scalars are heap-allocated.

1 Like