简体   繁体   中英

Is there a way to stop Julia using scientific (exponential) notation with BigFloats?

OK, I have what seems to be, on the face of it, a simple problem. I want to take the decimal part of an irrational number up to a specified number of digits and treat that as an integer. For example, if my irrational number is 2.657829... and I want five digits, I'm looking for 65782 (though I'm actually dealing with 'Big' numbers).

This is easily achieved using strings, for example if I wanted the decimal part of root 3 to 50 digits:

function main_1(n::Int, m::Int)::BigInt
    setprecision(Int(trunc((m + 3) * log2(10))))
    sr = string(sqrt(big(n)))
    ff = findfirst(sr, '.')
    dp = parse(BigInt, sr[ff + 1:ff + m])
    return dp
end

@time main_1(3, 50)

The output is 73205080756887729352744634150587236694280525381038 .

However, I resent using strings when I'm dealing solely with numbers! What I want to be able to do is start with a BigFloat, subtract the integer part, multiply the result by the appropriate factor of 10, round the result to zero, and then convert it to a BigInt. The problem is that Julia uses scientific / exponential notation, so I don't seem to be able to achieve what I want using only numbers. The following (partial) code shows the problem:

function main_2(n::Int, m::Int)::BigFloat
    setprecision(Int(trunc((m + 3) * log2(10))))
    sr = sqrt(big(n))
    tr = trunc(sr)
    dp = (sr - tr) * big(10.0) ^ 50
    return dp
end

@time main_2(3, 50)

The output in this case is 7.32050807568877293527446341505872366942805253810380625e+49 (there's a few extra digits that would have been removed at the rounding stage).

So my question is, is there any way to achieve my objective without resorting to strings?

One way to achive this, without using strings, is to convert the result and it's integer part to BigInt before do the subtract (and change the function type from BigFloat to BigInt ):

function main_2(n::Int, m::Int)::BigInt
    setprecision(Int(trunc((m + 3) * log2(10))))

    # Calc the sqrt
    result = sqrt(big(n))

    # Convert the whole number to BigInt to the specified precision
    sr = convert(BigInt, trunc(result*big(10)^m))

    # Convert the integer part to BigInt
    tr = convert(BigInt, trunc(result)*big(10)^m)

    dp = sr - tr
    return dp
end

Comparing the above implementation with the main_1 function, there is a little improvement:

julia> @time main_1(3, 50)
  0.000042 seconds (36 allocations: 5.254 KiB)
73205080756887729352744634150587236694280525381038

julia> @time main_2(3, 50)
  0.000028 seconds (51 allocations: 1.617 KiB)
73205080756887729352744634150587236694280525381038

Edit:

Other way (as commented by @Bill) is just trunc the result (to get rid of InexactError() ) and change the function type to BigInt :

function main_2(n::Int, m::Int)::BigInt
    setprecision(Int(trunc((m + 3) * log2(10))))
    sr = sqrt(big(n))
    tr = trunc(sr)
    dp = (sr - tr) * big(10.0) ^ 50
    return trunc(dp)
end

After testing:

julia> @time main_2(3,50)
  0.000026 seconds (28 allocations: 1.016 KiB)
73205080756887729352744634150587236694280525381038

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM