Hi, I am writing a program for a PIC 16f877. I must calculate some weather parameters and I have need to calculate the logarithm in base 10. Exists some formula/procedure that help me to generate a logarithm of a number between 10 and 100 with only 4 decimal digit? I know that the result is a real but then I will put it in more byte and display it. thanks for the info stefano
I'm not sure if I understand exactly what you're looking for, so I'll repeat the question back to you and you can correct it if I have misunderstood. What you want is an approximation of a log10 function with a maximum error of less than 1e-4 over the range (10,100). If that's correct, then there are a couple of ways to do that. One way would be to use an series approximation. One that will (mathematically) meet your requirements is
This has a maximum error of 0.7626633405e-4 in the range (10,100) but as you can see, it's a little complex (and probably quite slow) for a PIC to calculate. FYI, I generated this approximation in just a couple of seconds using Maple. (see
formatting link
) Specifically, I used the minimax function, but there are other means of turning trancendental functions into series approximations, e.g Chebyshev, (see
formatting link
) and and Pade-Chebyshev. (see
formatting link
and links). If you find calculus scary, don't look! :-)
The more usual method is to use a table lookup. Since you need so much precision, you'll have to use a table and interpolation. Conceptually, this is done by approximating the curve as a series of straight lines, and there are a couple of ways to "slice" the curve. One way is to divide up the curve at equally spaced intervals, and another way is to divide up the curve so that the straight line approximation between the two points is less than or equal to your desired error term. You might do it the first way to save on lookup time at the expense of ROM table size or the second way to economize a little on ROM at the expense of lookup time. (In some circumstances that require less precision than yours, you can use just a simple lookup.)
You can create the tables yourself with a simple program on your desktop machine. How you do it depends on a lot of things, not least of which is the number representation you decide to use in the PIC. Obvious options include fixed point and floating point, but floating point on a PIC is going to be painful if you haven't done this kind of thing before.
If this explanation doesn't help, try asking again with a little more detail.
In a binary computer, the logarithm is often easier to calculate in base 2, so only the interval (1,2) needs to be considered. The number is normalized into the interval by plain bit shifts, and the shift count remembered. The shift count is the integer part of base 2 logarithm to be added to the tabulated/interpolated result.
In any case, logarithm is the most complicated elementary function to calculate from a series.
Which format are your input data in?
For integers, by far the easiest way is a table with all the entries in the range you're interested, even though a constant table is a kind of PITA in a PIC.
Jack Crenshaw had an article on a clever way of calculating a base-2 logarithm in the March 1998 issue of Embedded Systems Programming. Also in his "Math Toolkit for Real-Time Programming" (ISBN 1-929629-09-5). There are a few descriptions on-line; google for "Crenshaw bitlog".
you have reason, only now i have understood that calculate the logarithms with series it is much complicated , I will have to reserve 90 cells of memory in order to insert the logarithms table
It's also in a form that's a bit easier for a computer to use.
However, I see that in another message you say that your inputs are integers. If that's the case and the range is only 10-100, you are definitely better off using a table! Here's a table version in C showing the values and also the approximate error terms which should all be less than 1e-4.
for (i=10; i < 101; i++) { x = 1.0 + (log10table[i-10]/65536.0); if (i > 31) x = x + 1.0; printf("%d\t%f\t%g\n", i, x, log10(i)-x); } return 0; }
There are ways to optimize this, of course, but this should get you started with something that works. Also, in the real code, don't forget about range checking! You don't want to go off the end of the table.
The artist formerly known as Ed Beroset wrote: | One way | would be to use an series approximation. One that will (mathematically) | meet your requirements is | | log10(x) = 0.215228608 + .1362859914*x - 0.8941598030e-2*x^2 + | 0.4317913455e-3*x^3 - 0.1439966989e-4*x^4 + 0.3302136507e-6*x^5
This equation can be reduced to 0.215228608 + x*(0.1362859914 - x*(0.894159803e-2 - x*(0.4317913455e-3 - x*(0.1439966989e-4 - x*(0.3302136507e-6)))))
This reduces the number of multiplications from 9 to 5.
--
MT
To reply directly, please first take your dick out of my address.
Keep in mind that a straight lookup table has almost no code, plus if you intend to display the result you can put the final display values in the table. If you implement a log10 algorithm it has to be smaller than a 90 element table (you did later say the input was integer, right?) if you want to save space.
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here.
All logos and trade names are the property of their respective owners.