Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement pow #12

Open
royNiladri opened this issue Jul 29, 2017 · 6 comments · May be fixed by #130 or #132
Open

Implement pow #12

royNiladri opened this issue Jul 29, 2017 · 6 comments · May be fixed by #130 or #132

Comments

@royNiladri
Copy link
Owner

Raise a number to another number. Both can be non integer and cases resulting in imaginary number [like bigDecimal.pow(-21, 0.5)] should throw an error.

@Jsoto22
Copy link
Collaborator

Jsoto22 commented Mar 26, 2024

I've been working on some vector stuff and needed your library to get around the whole floating-point issue. Despite using your library in other projects, I never needed precision powers or roots, so I came to the repo to just double check and didn't find those features. I was going to open a new Issue, and seen you already did.

Anyways, I did some research on how to calculate, technically approximate, powers and roots, and put together the functions bellow. It allows for "Imaginary Numbers", although it really just uses the absolute value of the Base, then negates the sign before returning the result. Similarly, negative exponents will take the reciprocal of the resulting power.

    import decimal from 'js-big-decimal';

    ...


    function nthRoot(x: number, n: number, g = 1, tolerance = 0.00001) {
      const one = new decimal(1);
      const X = new decimal(x);
      const N = new decimal(n);
      const a = N.subtract(one);

      let G = new decimal(g);

      while (true) {
        const b = new decimal(pow(Number(G.getValue()), n - 1));
        const c = X.divide(b);
        const d = a.multiply(G);
        const e = d.add(c);
        const next = e.divide(N);

        if (Number(next.subtract(G).abs().getValue()) < tolerance) {
          return Number(next.getValue());
        }
        G = next;
      }
    }

    function pow(x: number, n: number) {
      const imaginary = x < 0 && Math.abs(n) < 1;

      try {
        if (imaginary) {
          x = Math.abs(x);
          throw `Cannot calculate powers resulting in Imaginary Numbers. Base will be subsituted with it's absolute value, and result will be negated.`;
        }
      } catch (warning) {
        console.warn(warning);
      }

      const base = new decimal(x);
      const exp = new decimal(n);
      const floor = exp.floor();
      const remainder = exp.subtract(floor);

      let result = new decimal(x);

      if (
        Number(remainder.getValue()) > 0 &&
        Number(remainder.getValue()) < 1
      ) {
        const f = new decimal(1).divide(remainder, 3);
        const root = nthRoot(x, Number(f.getValue()));

        if (Number(floor.getValue()) > 0) {
          for (let i = 0; i < Number(floor.getValue()) - 1; i++) {
            result = result.multiply(base);
          }
        } else {
          result = new decimal(1);
        }

        result = result.multiply(new decimal(root));
      } else {
        for (let i = 0; i < Number(floor.getValue()) - 1; i++) {
          result = result.multiply(base);
        }
      }

      result = imaginary ? result.negate() : result;
      result = n < 0 ? new decimal(1).divide(result) : result;
      return Number(result.getValue());
    }

I'm hesitant to fork the project and try to implement this myself, but I hope @royNiladri or any other contributors will find this helpful. Given the robustness of the codebase, I'm sure the core functions can be used as to replicate these methods without needing to add too much more.

@royNiladri
Copy link
Owner Author

Hi. If you have some bandwidth, do you mind creating a pull request with your suggested changes? We can integrate it in the library then🙂

@Jsoto22
Copy link
Collaborator

Jsoto22 commented Mar 26, 2024

I can do so maybe tonight. It definitely needs to be refined and heavily tested. The method tends to throw itself into an infinite loop in certain cases, but I came across a few way to do the approximations, so if this method doesn't work out, I'll try the others. I'll update this issue as I progress in the meantime. Don't want to submit a pull request that introduces something that may completely change.

@Jsoto22
Copy link
Collaborator

Jsoto22 commented Mar 27, 2024

Update: I got it to work but some fractional exponents cause the recursive nth-root pow call to overflow the stack at times and takes several minutes to complete in others. Otherwise, it works with a fair bit of accuracy but the higher the accuracy, the more likely it will take longer to complete or just overflow.

I'll push an integer exponent only version tonight and submit a pull request on that. Tomorrow I'll try to implement a Taylor series method that doesn't use the reclusive pow in the nth-root for calculating fractional exponents. No promises but I should have something working and tested by Friday.

As a side note, the Taylor series method will allow the user to define the number of steps in the logarithm, equating to the amount of precision (more so accuracy within one or two decimal places at the end). Given everything, I was able to find, most math libraries and API's use these methods behind the scenes, so it would be realistically no different than using those with the added advantage of using the precision of the functions in this project.

Reference to NthRoot Method

@royNiladri
Copy link
Owner Author

Hi @Jsoto22 ,
I have created a pre-release branch for April. I am making some minor changes (tests and stuff). If you plan to do more changes, please raise PR to this branch (Rel/2024-03 m1). (This should go to a major release)
#130

It would be great if you can wrap up the whole thing before we publish, but if you have time crunch, do let me know, we will publish in current state with notes in readme about what currently works, and what is pending implementation.

Once again, thanks for taking this up! :)

@royNiladri royNiladri linked a pull request Mar 31, 2024 that will close this issue
2 tasks
@Jsoto22
Copy link
Collaborator

Jsoto22 commented Apr 1, 2024

@royNiladri You're welcome and will do.

@Jsoto22 Jsoto22 linked a pull request Apr 21, 2024 that will close this issue
4 tasks
@Jsoto22 Jsoto22 linked a pull request Apr 21, 2024 that will close this issue
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging a pull request may close this issue.

2 participants