Issue with BigFloat rounding

I want to set the BigFloat(7.0687866210937500e-1) by using a precision of 15 bits and two different rounding modes (up and down). So I do:

setprecision(15)
setrounding(BigFloat, RoundDown) # or RoundUp
BigFloat(7.0687866210937500e-1)

and I get both times the same result: 0.706879.
However, using the mpfr package in C I get 0.706878 and 0.706879 for rounding down and up respectively. Any ideas why this happens ?

Thanks !

Often when working with BigFloat literals you want to be using strings — floating point literals are immediately Float32 or Float64 before going to the BigFloat constructor. But that’s not the problem here, because you’re using fewer bits.

julia> setprecision(15)
15

julia> BigFloat("7.0687866210937500e-1", RoundDown)
0.706879

julia> BigFloat("7.0687866210937500e-1", RoundUp)
0.706879
1 Like

Thanks for your reply ! So the rounding down or up concerns only the passage from string to a Float32 or Float64 ?
How can I get in julia the analog of MPFR_RNDD and MPFR_RNDU (that I use in C), when creating the BigFloat ?

This is exactly representable with a precision of 15 bits, so the rounding mode doesn’t matter (because there’s no rounding). I think this is just some kind of printing issue.

julia> setprecision(10000)
10000

julia> big = BigFloat("7.0687866210937500e-1")
0.706878662109375

julia> f64 = 7.0687866210937500e-1
0.706878662109375

julia> small = BigFloat("7.0687866210937500e-1", precision = 15)
0.706879

julia> big == f64 == small
true

julia> precision.((big, f64, small))
(10000, 53, 15)
1 Like

BTW please use code block Markdown to make your post readable. Finds instructions and other tips here:

Yeah. Almost all functions in the MPFR API take rounding modes, including the output functions. So I guess everything here is as expected, although the initial post was unclear. What exactly is your goal, @chkat?

It confuses me how it happens that the printing in C, using two different rounding modes, gives two different decimals (0.706878 and 0.706879) but in Julia there is no difference:

julia> BigFloat(7.0687866210937500e-1, RoundDown, precision=15)
0.706879

julia> BigFloat(7.0687866210937500e-1, RoundUp, precision=15)
0.706879

Can you post your C-program? As noted above, the number 7.0687866210937500e-1 == 23163/2^15, so ideally no rounding should take place as demonstrated by @nsajko above. Unless “precision” means different things in the C-program and in julia.

1 Like

This is OK, and the Julia code is also OK. I think you’re just missing (sorry for not being clear before) the distinction between printing and construction in Julia. In your C code you seem to give a rounding mode to the MPFR printing/output routines, but in Julia you don’t do that (and I’m not sure if it’s possible to do currently). Thus the different behavior.

NB: in your Julia examples the printing happens automatically/implicitly because of the REPL.

What is your goal here? Why do you need rounding modes for printing?

2 Likes
#include<mpfr.h>

int main(){
    mpfr_t a;
    mpfr_init2(a, 15);
    mpfr_set_d(a, 7.0687866210937500e-1, MPFR_RNDD);
    mpfr_out_str(stdout,10, 0, a, MPFR_RNDD); // gives 7.06878e-1
    mpfr_out_str(stdout,10, 0, a, MPFR_RNDU); // gives 7.06879e-1
}

Ah, ok. So in the C-program the float isn’t rounded, but you specify that the output should be 10 characters wide. Consequently, some decimals may have to be suppressed. The rounding specifies what should be done with the preceding decimal. Should it be rounded up or down?

In julia, you specify how the Float64 should be moved into a BigFloat of precision 15. It’s not necessary to do any rounding, it fits exactly with a 15 bit significand. So no rounding occurs. The BigFloat is created.

Now, julia prints the result of the last operation. It gets a BigFloat, the same BigFloat regardless of what rounding you specified, and prints it with whatever rules for printing it has. Some looking around seems to indicate that a call to string_mpfr(x, "%Re") is done, followed by _prettify_bigfloat, whatever that is.

3 Likes

Just because you mentioned it, in

mpfr_out_str(stdout,10, 0, a, MPFR_RNDD);

the 10 is the base, not the number of characters.

So, if I understand well, what you and @nsajko say is that it is a printing issue.
In Julia, string_mpfr in turn calls the C-function mpfr_asprintf but that does not take the rounding as a parameter. A possible workaround to be able to obtain the rounding option when printing, would be to call the mpfr_out_str function via Julia, no ? But this I find complicated still, I do not know what is the corresponding type for FILE *streamin Julia and how I can set it to stdout.

Thanks a lot for your answers in any case !

1 Like

The mpfr sprintf-functions takes rounding mode in their specifications, so it should be possible to use them.

2 Likes

Yes, this works, thanks a lot ! I can edit the format specifier “%Re” to include the rounding:

julia> using Base.MPFR

julia> MPFR.string_mpfr(x, "%Re")
"7.06879e-01"

julia> MPFR.string_mpfr(x, "%RDe")
"7.06878e-01"

julia> MPFR.string_mpfr(x, "%RUe")
"7.06879e-01"


2 Likes

Just keep in mind that technically, this API isn’t supported. That is, there’s a chance it could stop working after an update of Julia. Personally I think that’s not very likely to happen soon, but keep it in mind.

Formally, if you were to use MPFR.string_mpfr in a package meant for use by others, you should whitelist tested versions of Julia in the package’s Project.toml, instead of relying on Semver.

1 Like