4 ms·
I've just started getting into Julia for one of it's best use cases: It's super easy to do arbitrary precision math. But you have to be very careful when using
by kloch 3y ago
I've just started getting into Julia for one of it's best use cases: It's super easy to do arbitrary precision math. But you have to be very careful when using string literals with BigInt or BigFloat:
julia> setprecision(1024)
julia> a=BigFloat(1.0E-300)
1.000000000000000025059091835208759685696146807703705249925342319900466043184051484676302812181950100894962306270278254148910311464998804130812246091606190182719426627934584275510414782787015070222639260603793613924359775094030143866141479125513590882591017341692222921220404918621822029155619541859418525883262e-300
Notice without quotes on the literal you only get ~15 decimal digits of precision because the parser treats the literal as a double and then passes that to the BigFloat variable.
julia> a=BigFloat("1.0E-300")
9.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999988e-301
With quotes we get the full ~308 decimal digits of precision for the configured 1024-bit binary precision.
Now we can add it to 1.0 to validate the precision of a calculation and use the @printf macro for C-style formatting to round the output to 308 decimal digits:
julia> b=BigFloat("1.0")
julia> using Printf
julia> @printf("%.308f\n", (a+b))
1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000
I'm not sure why this is the default behavior, it seems like a really easy way for people to screw up their calculations, especially scientists that don't do a lot of programming.
- DNF2 3y agoI actually find the string macro syntax even more convenient: `big"1e-300"`.
- wnoise 3y ago> I'm not sure why this is the default behavior, Um. You said the answer earlier: > because the parser treats the literal as a double BigFloats aren't built in to the syntax of the language (and probably should't be, so you need to escape the parser somehow -- either pass a string to the constructor, or use the @big_str macro to get a non-standard string parsed into a BigFloat.
- kloch 3y agoThis makes perfect sense from the perspective of a language designer/computer scientist who is trying to keep their design clean and consistent. It makes no sense to an end user that expects an argument you pass to BigFloat to be treated as a BigFloat. As an end-user I would rather have a warning or even error than to have my argument silently treated as a double.
- sundarurfriend 3y agoIt's a tricky case because they do provide the `big""` macros for literals, and mention in BigFloat's docs that: BigFloat(x::AbstractString) is identical to parse. This is provided for convenience since decimal literals are converted to Float64 when parsed, so BigFloat(2.1) may not yield what you expect. ... Examples ≡≡≡≡≡≡≡≡≡≡ julia> BigFloat(2.1) # 2.1 here is a Float64 2.100000000000000088817841970012523233890533447265625 However, saying RTFM is not a solution, especially for not-too-frequent parts of the language like BigFloats. It's still a trap many people are going to fall for. The solution here is a good linter though, not adding more work to the already overstressed compiler. It comes back to the issue of Julia needing more mature, easy-to-work-with tooling, that could say "hey, this is technically allowed, but you probably didn't mean this".
- DNF2 3y agoThe argument isn't silently treated as a double, it is explicitly and loudly treated as a double, because it is a literal double. And this is not an advantage to the designer exclusively, it is very much an advantage for the end user that the treatment is explicit, consistent and predictable, instead of 'magically' reinterpreting the meaning of literals based on guessing the intent of the user. Basically, you seem to be saying that when passing x to BigFloat, x should not be treated as the value x, but as some nearby value that might be the one the caller intended (based on some rounding logic perhaps?) Or are you perhaps saying that x = 1e-300 y = BigFloat(x) should be different from y = BigFloat(1e-300) ? In other words, completely discarding referential transparency?
- 3y ago