1
\$\begingroup\$

I have problem calculating raise a to the power of b (a^b) where b is a floating point number.
In my case, b=-1.45. So the expression is a^(-1.45).
I'm using PIC18F4520 microcontroller and I don't know how to implement it in assembly language or its routine as well.

\$\endgroup\$
10
  • \$\begingroup\$ Which sort of PIC? Does it actually have a floating point instruction set? \$\endgroup\$
    – pjc50
    Jun 2 '20 at 10:41
  • \$\begingroup\$ PIC18F4520 is the one i'm using \$\endgroup\$
    – Thanh Nhon
    Jun 2 '20 at 10:42
  • \$\begingroup\$ It's quite unusual to use floating point in small microcontrollers. Perhaps if you described your higher-level problem we might be able to advise. If you really need it, find a suitable FP library. Implementing exponentiation is not straightforward. Standard reference is Knuth Volume 2 section 4.6.3. en.wikipedia.org/wiki/The_Art_of_Computer_Programming \$\endgroup\$
    – jonathanjo
    Jun 2 '20 at 10:55
  • 2
    \$\begingroup\$ @STUDENTSTRANGE I used to code assembly for the PIC18F. It does include C compilers that support FP libraries, of sorts. Is there a reason you need to code this in assembly and without using library code of some kind? \$\endgroup\$
    – jonk
    Jun 2 '20 at 11:00
  • 2
    \$\begingroup\$ Are you saying your value of a a 16-bit integer? Or that it's 8 bit + 8 bit fixed point? Or something else? Can a be negative? What sort of format do you want the result in? Tables with or without interpolation are the way to deal with it, but without detail it's hard to say more. \$\endgroup\$
    – jonathanjo
    Jun 2 '20 at 13:44
5
\$\begingroup\$

Note that just because b isn't an integer, it doesn't mean that it is necessarily floating-point. For example, it could be expressed as the integer ratio \$-1.45 = \frac{-29}{20}\$.

You need to specify what the type and range of a is, and what kind of accuracy you require in your application. You also haven't specified what you want the output to look like. As @jonathanjo pointed out, all answers except for a=1 are fractions less than 0.5. Also, since exponentiation is a nonlinear operation, it's important to understand what real-world values the integer values of 'a' represent.

For what it's worth, arbitrary exponentiation is usually implemented as a 3-step process: log, multiply, exponentiate:

$$a^b \equiv \exp(b \cdot \log(a))$$

You can use any convenient base for the log() and exp() operations, as long as they're the same. 2, \$e\$ and 10 are popular choices.

CORDIC is one way to implement log() and exp() on small systems. See also .

But depending on your requirements, piecewise linear or polynomial approximation of the overall function might be more appropriate. These just require a few multiplies and adds. It's also possible that \$\frac{1}{polynomial}\$ or \$\frac{1}{\sqrt{polynomial}}\$ would be a good fit for your function. These operations are similarly easy to add to the mix using Newton-Raphson.

\$\endgroup\$
11
  • \$\begingroup\$ Thanks @Dave Tweed, I'm trying to look for a equivalent expression of mine. I don't require high precision so an approximate one is fine. Do you have any suggestion? \$\endgroup\$
    – Thanh Nhon
    Jun 2 '20 at 17:01
  • \$\begingroup\$ You still haven't specified what you want the output to look like. As @jonathanjo pointed out, all answers except for a=1 are fractions less than 0.5. Also, since exponentiation is a nonlinear operation, it's important to understand what real-world values the integer values of 'a' represent. \$\endgroup\$
    – Dave Tweed
    Jun 2 '20 at 20:40
  • \$\begingroup\$ If one is only interested in raising to one particular exponent, a log/mul/exp sequence is probably not going to be as efficient as an approach designed for that exponent. Depending upon the range of values involved, computing 1/sqrt(x*x*x) and possibly applying a fudge factor may be adequate. \$\endgroup\$
    – supercat
    Jun 2 '20 at 22:41
  • \$\begingroup\$ @supercat: True, but this feels like some sort of sensor linearization application, so I'm not assuming that the exponent is a compile-time constant. It may be a calibration value read out of EEPROM or something. \$\endgroup\$
    – Dave Tweed
    Jun 2 '20 at 22:46
  • 1
    \$\begingroup\$ Also, you came here looking for a way to do \$a^b\$ in assembly language. Now you're saying that simpler operations like \$\ln(x)\$, \$e^x\$ and \$\sqrt{x}\$ are simply not possible in assembly. This is REALLY not making any sense. I think I'm done here. \$\endgroup\$
    – Dave Tweed
    Jun 3 '20 at 4:10
4
\$\begingroup\$

PIC18F 8-bit system with no floating point. So it's not going to be a few instructions. You've also not specified how much precision you want (32 bits? 64?)

Your options are:

  • find a suitable library, possibly from Microchip, possibly from their C compiler, and use that

  • find an approximation: if the value of the exponent is fixed, you might be able to do it by Taylor series expansion

  • lookup table: if a is an 8-bit value, you could just have a table of the possible answers pre-computed.

Either way it's going to be slow.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks @pjc50 ! I found your second solution is a suitable one with my project. I do not require high precision with final result. So an approximation maybe work for me because the exponent is constant in fact. But i saw that Taylor has derivation so how come we do that in asm or is there a reduced equation for this case? \$\endgroup\$
    – Thanh Nhon
    Jun 2 '20 at 16:58
  • 1
    \$\begingroup\$ @STUDENTSTRANGE While the Taylor expansion does contain the derivative of the function, it only contains the derivative at fixed positions that do not depend on the value of a. You do not calculate these derivates on the target processor at run time, but you calculate the derivative(s) while you write your assembler code and put the result into your code. \$\endgroup\$ Jun 3 '20 at 0:10
  • \$\begingroup\$ I still don't grasp your idea. Could you explain more detail about your way? \$\endgroup\$
    – Thanh Nhon
    Jun 3 '20 at 2:13
  • 1
    \$\begingroup\$ @pjc50 you might consider edit to indicate that table lookup is actually fast, albeit restricted. \$\endgroup\$
    – jonathanjo
    Jun 3 '20 at 10:54
2
\$\begingroup\$

I deleted this yesterday as it was downvoted for thinking the result was an integer. I've restored it in the light of OP's clarification that the result is indeed wanted as an integer.

The function as you have described it is

  • f = round(a^-1.45) with a an integer
  • Based on your comments
    • "Value of 'a' is stored in 16 bit registors .... It's an integer"
    • "I want result to be a round number, that means if its decimal part is larger than 5, integer part will be increment 1 unit. Otherwise, the decimal part is omitted. Therefore, final result will be an integer"

This is really quite a strange requirement, because a^-1.45 doesn't have very interesting values for integers, as you can see from this graph:

enter image description here
https://www.symbolab.com/graphing-calculator?functions=y=x%5E%7B-1.45%7D

It has the following values:

0      divide-by-zero error
1      1.000
1.613  0.500 
2      0.366
3      0.203
>3     even smaller
<0     complex numbers

But if it's actually what you want it's trivial to implement. Your code can be modelled on the following, trivial to implement in any language:

define f(x)
  if x < 0 then return ERROR_COMPLEX;
  if x == 0 then return ERROR_DIV0;
  if x == 1 then return 1;
  return 0

If it's not actually what you want you need to edit your question with with a higher level goal so we can help. It might be that the "right answer" is a) input or output not actually integers, b) function is not needed because it's not an important part of the larger problem, c) something else.

\$\endgroup\$
0
\$\begingroup\$

The PIC 18 don't have a floating point unit, so you had do use a floatingpoint library. Maybe have a look a microchips AN660.
Another option is to switch to a c compiler which supports floating point. e.g. the xc8 from microchip.

But as @jonathhanjo mentioned, this is really unusual on such a small controller.

\$\endgroup\$
1
  • \$\begingroup\$ Your AN660 reference is an excellent reference. \$\endgroup\$
    – jonathanjo
    Jun 2 '20 at 13:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.