tst
tst

Reputation: 1172

Julia: Inexact error when trying to get the integer part of a BigFloat

I am interested in getting the digits of a BigFloat in the form of bytes. I get a very strange error that I cannot debug. I provide a minimal example where the error appears.

function floatToBytes(x::BigFloat)
  ret = zeros(UInt8, 4)
  xs = significand(x)/2
  b = UInt8(0)
  for i = 1:4
    xs *= 256
    b = trunc(UInt8, xs)
    ret[i] = b
    xs -= b
  end
  return ret  
end

println( floatToBytes(BigFloat(0.9921875001164153)) )
println( floatToBytes(BigFloat(0.9960937501164153)) )

What I get when running this is

UInt8[0xfe, 0x00, 0x00, 0x00]
ERROR: LoadError: InexactError()
Stacktrace:
 [1] trunc(::Type{UInt8}, ::BigFloat) at ./mpfr.jl:201

etc.

It seems that it doesn't want to turn 255 into a UInt8. I can circumvent the problem by defining the function as

function floatToBytes(x::BigFloat)
  ret = zeros(UInt8, 4)
  xs = significand(x)/2
  b = UInt8(0)
  for i = 1:4
    xs *= 256
    try
      b = trunc(UInt8, xs)
    catch
      b = trunc(UInt8, xs-1)+UInt8(1)
    end
    ret[i] = b
    xs -= b
  end
  return ret  
end

But this is highly unsatisfactory. What is going on here?

Upvotes: 1

Views: 1091

Answers (1)

Dan Getz
Dan Getz

Reputation: 18217

The problem looks like a bug in trunc for BigFloat. The problem is the current code does (typemin(T) <= x <= typemax(T)) || throw(InexactError(:trunc, T, x)) which throws an error because x is larger than 255 which is the typemax.

It actually needs to do the trunc in BigFloat domain and then cast to T (and have the cast check for typemax).

I've opened an issue regarding this at: https://github.com/JuliaLang/julia/issues/24041

In the meantime, a solution could be to do:

UInt8(trunc(xs))

i.e. trunc first and cast later. For example:

julia> UInt8(trunc(BigFloat(0.9960937501164153)*256))
0xff

Upvotes: 3

Related Questions