Numerical accuracy/machine accuracy and roundness in Julia

Dear community,
I am new to the forum and I’m looking for a good option for how I can round Julia’s machine accuracy for polynomials or simplify the numbers in the system. I am concerned with the following problems:

I use the package https://github.com/JuliaAlgebra/DynamicPolynomials.jl and would like to save, for example: DynamicPolynomials.Polynomial[1.0000000000000002 + 1.00000000000000004x₂ + 1.1102230246251563e-16x₁ - 2.0000000000000004x₁x₂ - 2.0000000000000004x₁²] as

‘1.0 + 1.0x_2 + 0.0x_1 - 2.0x_1x_2 - 2.0x_1^2.’

Do you have any idea for me how to implement this well?
Thank you very much for your effort!

Maybe a little clearer, how can I round
1.0000000000000002 to 1.0 or
1.1102230246251563e-16 to 0.0

thanks

Hi, and welcome to the Julia community!

I’m not saying this is necessarily a ‘good’ solution as there is no clear universal meaning of closeness in this setting (see e.g. discussions about isapprox), but you could use round(..., digits=...) or round(..., sigdigits=...):

julia> round(1.0000000000000002, digits=5)
1.0

julia> round(1.1102230246251563e-16, digits=5)
0.0
4 Likes

Two questions:

  • Is your intent that all of the coefficients be integers?
  • Is your intent to change the coefficients being used for calculations, or simply to print them without the additional digits?
1 Like

As an intermediate step, I would like to simplify this polynomial and then continue my calculations with it. Because this not only increases calculation speed but also simplifies the equations to be calculated.

The simple command round(a) will round a floating-point value a to the nearest integer-valued floating-point number, e.g. round(5.000000000001) == 5.0 but also round(0.75) == 1.0. If that’s desirable, you may also benefit from an explicit conversion to integer data types, e.g. Int(round(a))

The source for that package is a little tough to follow, but it sounds like maybe you’re looking to perform something like

using DynamicPolynominals
poly = Polynomial(...)
rounded_poly = Polynomial(Int.(round.(poly.a)), poly.x)

where the dots before parenthesis are used for broadcasting.

2 Likes

Rounding (without changing types) should not make a difference in this regard, i.e. the computer is equally happy to perform calculations with 5. as it is with 5.1234321. So if this is your main motivation, there is no need to worry about encountering ‘long’ numbers :slight_smile: .

2 Likes

If this is for output purposes, the best thing is not to use round (which rounds the internal binary representation), but rather to use @printf (which rounds the decimal-output representation) and related functions from the Printf standard library.

For computational purposes, however, rounding intermediate steps is probably actively a bad idea (not only is it not faster, but it can cause catastrophic loss of accuracy if you are not careful). If for some reason you need to ensure exact integer or rational answers, you need to use exact computations from the beginning (and it will probably be slower).

5 Likes

Such as, for example, Rational{BigInt}.

That’s a good option. Unfortunately, there are not only integers. The goal is to calculate the basis functions for the finite element analysis. There are also 0.25 or something else. For example:

0.25000000001100e10 -> 0.25

round() is probably not an elegant solution, but I will test whether it serves its purpose.

Is there a possibility that we can connect round(..., digits=...) with this one?

using DynamicPolynominals
poly = Polynomial(...)
rounded_poly = Polynomial(Int.(round.(poly.a)), poly.x)

So that we are not only able to do integer rounding but also any other possible?

Just use Rational instead of AbstractFloat, then convert it to Float64 or whatever when that’s OK to do.

1 Like

You mean like

rounded_poly = Polynomial(round.(poly.a, digits=2), poly.x)

?

1 Like