Derivasians / Calculatte

A simple to use numerical Java calculus library.
https://derivasians.github.io/Calculatte
Apache License 2.0
1 stars 0 forks source link

Duplicate rounding causes inaccuracy #3

Closed SoupyzInc closed 3 years ago

SoupyzInc commented 3 years ago

Certain methods in Calculatte require other methods to work; e.g., the revolve() method uses the integrate() method. This causes accuracy issues where a value can be incorrectly rounded twice. This occurred during testing of the polarArea() method.

With the problem below, a value of 0.785 was expected (when rounded to 3 decimal places).

\frac{1}{2}\cdot\int_{0}^{\pi}(sin(\theta))^{2}d\theta=\frac{\pi}{4} (Symbolab)%5E%7B2%7Dd%5Ctheta)

However, during testing ,polarArea() returned 0.786.

Steps to reproduce

// TEST
@Test
@DisplayName("Polar integrate sin(x) from 0 to Pi")
public void polarIntegrateSineXFrom0ToPi() {
    Function SinX = x -> Math.sin(x);
    double area = Calculatte.polarArea(0, Math.PI, SinX);
    assertEquals(0.785, area);
}
// OUT
org.opentest4j.AssertionFailedError: 
Expected :0.785
Actual   :0.786

Causation of behavior The polarArea() method calls the the integrate() method. When this call occurs, the integrate() method will round its returned value. The integrate() method was supposed to evaluate

\int_{0}^{\pi}(sin(x))^{2}dx=\frac{\pi}{2} (Symbolab)%5E%7B2%7Ddx)

However, instead of returning 1.57079, the value gets rounded and is returned as 2.0. This incorrect value is then fed back into the polarArea() method, causing the inaccuracy issue.

Solution Create a second integrate() method that does not round values. This second method can be called integrateRaw() as it returns the raw value of calculation. All methods that use another method in their calculations will use the "raw" version of the method in order to avoid duplicate rounding.

The temporary solution being implemented currently is to disable rounding by setting CalculatteEnvironment.INTEGRATION_ROUNDING_DECIMAL_PLACES to -1, disabling integration rounding; then returning the value to 3.

It should be noted that this temporary solution does not account for the rounding value being changed by the user and is very hard to read.

Solution Integration The solution can be integrated after PR #4 has been merged with the temporary solution. That way, a new branch can be opened to resolve this issue. I have a feeling that further testing will have to be done in order to fully resolve this problem. It should also be noted that methods other than polarArea() will likely have to integrate this change as well.

/cc @jojongx