I created this function CalculateCos:
int Factorial (long int n)
{
long int r = 1;
for (int i = 2; i<=n; i++)
{
r = r*i;
}
return r;
}
float CalculateVariable(int CVnumber, int CVloopCounter)
{
float CVresult = 0;
CVresult = pow(CVnumber, (CVloopCounter*2)) / (long int)Factorial(CVnumber*2);
return CVresult;
}
float CalculateCos(int number)
{
float result = 1;
int loopCounter = 1;
int minusOrPlus = 1;
while(loopCounter <= precision && loopCounter <= 8)
{
if(!minusOrPlus)
{
result = result - CalculateVariable(number, loopCounter);
printf("%f\n", result);
minusOrPlus = 1;
}
else
{
result = result + CalculateVariable(number, loopCounter);
printf("%f\n", result);
minusOrPlus = 0;
}
loopCounter++;
}
return result;
}
The reason why I printf after the subtraction or adding, is because it gives me strange output, like:
Enter a number, for the cos function
6
1.000000
0.999997
1.000095
0.996588
1.122822
-3.421593
160.177368
-5729.385254
Result is: -5729.3852539
Official function result is: 0.9601703
Can you help me to get correct results on this?
UPDATE:
Now my solution is:
float CalculateCos(float number)
{
float result = 0;
float step = 1;
int loopCounter = 1;
while(loopCounter <= 5)
{
step = step * (-number) * number / (((2*loopCounter)-1)*((2*loopCounter)-2));
result += step;
loopCounter++;
}
return result;
}
Current problem:
since your Factorial function returns int and you casts it to long int, its result is going to overflow even before the input goes to 16 in your case (14! > max_int).
You're calculating cos using Taylor series:
cos(x) = 1 - x2/2! + x4/4! - x6/6!
+ ...
I'm not going to write code. But there are some things wrong in your program, which can be fixed easily:
The input is in radian, so number should be a float.
Calculating each step of Taylor series using exponentiation and factorial separately leads to overflow very soon. The correct way is maintaining a float variable: step = 1 at first and in kth loop iteration step = step * (- x) * x / ((2*k-1)*(2*k)). In this way, you simply add step to result in the loop and don't need minusOrPlus anymore.
The number of loop iterations is bounded by 8 which is too small, so the result could be not precise enough.
I don't see you use precision variable anywhere. It could be used to check precision of the result. For example, when abs(step) < precision, we're going to terminate the loop.
Related
I'm trying to code a program that can tell apart real and fake credit card numbers using Luhn's algorithm in C, which is
Multiply every other digit by 2, starting with the number’s
second-to-last digit, and then add those products’ digits together.
Add the sum to the sum of the digits that weren’t multiplied by 2.
If the total’s last digit is 0 (or, put more formally, if the total
modulo 10 is congruent to 0), the number is valid!
Then I coded something like this (I already declared all the functions at the top and included all the necessary libraries)
//Luhn's Algorithm
int luhn(long z)
{
int c;
return c = (sumall(z)-sumodd(z)) * 2 + sumaodd(z);
}
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a;
while(x)
{
a = a + x % 10;
x /= 100;
}
return a;
}
//sum of all digits
int sumall(long y)
{
int b;
while(y)
{
b = b + y % 10;
y /= 10;
}
return b;
}
But somehow it always gives out the wrong answer even though there's no error or bug detected. I came to notice that it works fine when my variable z stands alone, but when it's used multiple times in the same line of code with different functions, their values get messed up (in function luhn). I'm writing this to ask for any fix I can make to make my code run correctly as I intended.
I'd appreciate any help as I'm very new to this, and I'm not a native English speaker so I may have messed up some technical terms, but I hope you'd be able to understand my concerns.
sumall is wrong.
It should be sumeven from:
Add the sum to the sum of the digits that weren’t multiplied by 2.
Your sumall is summing all digits instead of the non-odd (i.e. even) digits.
You should do the * 2 inside sumodd as it should not be applied to the other [even] sum. And, it should be applied to the individual digits [vs the total sum].
Let's start with a proper definition from https://en.wikipedia.org/wiki/Luhn_algorithm
The check digit is computed as follows:
If the number already contains the check digit, drop that digit to form the "payload." The check digit is most often the last digit.
With the payload, start from the rightmost digit. Moving left, double the value of every second digit (including the rightmost digit).
Sum the digits of the resulting value in each position (using the original value where a digit did not get doubled in the previous step).
The check digit is calculated by 10 − ( s mod 10 )
Note that if we have a credit card of 9x where x is the check digit, then the payload is 9.
The correct [odd] sum for that digit is: 9 * 2 --> 18 --> 1 + 8 --> 9
But, sumodd(9x) * 2 --> 9 * 2 --> 18
Here's what I came up with:
// digsum -- calculate sum of digits
static inline int
digsum(int digcur)
{
int sum = 0;
for (; digcur != 0; digcur /= 10)
sum += digcur % 10;
return sum;
}
// luhn -- luhn's algorithm using digits array
int
luhn(long z)
{
char digits[16] = { 0 };
// get check digit and remove from "payload"
int check_expected = z % 10;
z /= 10;
// split into digits (we use little-endian)
int digcnt = 0;
for (digcnt = 0; z != 0; ++digcnt, z /= 10)
digits[digcnt] = z % 10;
int sum = 0;
for (int digidx = 0; digidx < digcnt; ++digidx) {
int digcur = digits[digidx];
if ((digidx & 1) == 0)
sum += digsum(digcur * 2);
else
sum += digcur;
}
int check_actual = 10 - (sum % 10);
return (check_actual == check_expected);
}
// luhn -- luhn's algorithm using long directly
int
luhn2(long z)
{
// get check digit and remove from "payload"
int check_expected = z % 10;
z /= 10;
int sum = 0;
for (int digidx = 0; z != 0; ++digidx, z /= 10) {
int digcur = z % 10;
if ((digidx & 1) == 0)
sum += digsum(digcur * 2);
else
sum += digcur;
}
int check_actual = 10 - (sum % 10);
return (check_actual == check_expected);
}
You've invoked undefined behavior by not initializing a few local variables in your functions, for instance you can remove your undefined behaviour in sumodd() by initializing a to zero like so:
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a = 0; //Initialize
while(x)
{
a += x % 10; //You can "a += b" instead of "a = a + b"
x /= 100;
}
return a;
}
It's also important to note that long is only required to be a minimum of 4-bytes wide, so it is not guaranteed to be wide enough to represent a decimal-16-digit-integer. Using long long solves this problem.
Alternatively you may find this problem much easier to solve by treating your credit card number as a char[] instead of an integer type altogether, for instance if we assume a 16-digit credit card number:
int luhn(long long z){
char number[16]; //Convert CC number to array of digits and store them here
for(int c = 0; c < 16; ++c){
number[c] = z % 10; //Last digit is at number[0], first digit is at number[15]
z /= 10;
}
int sum = 0;
for(int c = 0; c < 16; c += 2){
sum += number[c] + number[c + 1] * 2; //Sum the even digits and the doubled odd digits
}
return sum;
}
...and you could skip the long long to char[] translation part altogether if you treat the credit card number as an array of digits in the whole program
This expression:
(sumall(z)-sumodd(z)) * 2 + sumall(z);
Should be:
((sumall(z)-sumodd(z)) * 2 + sumodd(z))%10;
Based on your own definition.
But how about:
(sumall(z) * 2 - sumodd(z))%10
If you're trying to be smart and base off sumall(). You don't need to call anything twice.
Also you don't initialise your local variables. You must assign variables values before using them in C.
Also you don't need the local variable c in the luhn() function. It's harmless but unnecessary.
As others mention in a real-world application we can't recommend enough that such 'codes' are held in a character array. The amount of grief caused by people using integer types to represent digit sequence 'codes' and identifiers is vast. Unless a variable represents a numerical quantity of something, don't represent it as an arithmetic type. More issue has been caused in my career by that error than people trying to use double to represent monetary amounts.
#include <stdio.h>
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a=0;
while(x)
{
a = a + x % 10;
x /= 100;
}
return a;
}
//sum of all digits
int sumall(long y)
{
int b=0;
while(y)
{
b = b + y % 10;
y /= 10;
}
return b;
}
//Luhn's Algorithm
int luhn(long z)
{
return (sumall(z)*2-sumodd(z))%10;
}
int check_luhn(long y,int expect){
int result=luhn(y);
if(result==expect){
return 0;
}
return 1;
}
int check_sumodd(long y,int expect){
int result=sumodd(y);
if(result==expect){
return 0;
}
return 1;
}
int check_sumall(long y,int expect){
int result=sumall(y);
if(result==expect){
return 0;
}
return 1;
}
int main(void) {
int errors=0;
errors+=check_sumall(1,1);
errors+=check_sumall(12,3);
errors+=check_sumall(123456789L,45);
errors+=check_sumall(4273391,4+2+7+3+3+9+1);
errors+=check_sumodd(1,1);
errors+=check_sumodd(91,1);
errors+=check_sumodd(791,8);
errors+=check_sumodd(1213191,1+1+1+1);
errors+=check_sumodd(4273391,15);
errors+=check_luhn(1234567890,((9+7+5+3+1)*2+(0+8+6+4+2))%10);
errors+=check_luhn(9264567897,((9+7+5+6+9)*2+(7+8+6+4+2))%10);
if(errors!=0){
printf("*ERRORS*\n");
}else{
printf("Success\n");
}
return 0;
}
I am making simple calculator and it is e^x function part.
it works for positive number, but it doesn't for negative x.
How can I make it works for negative x too?`
double calculateEx(double x) {
double beforeResult = 1, afterResult = 1, term = 1, error = 1, i = 1, j;
while (error > 0.001) {
afterResult = beforeResult;
for (j = 1; j <= i; j++) {
term *= x;
}
term /= fact(i);
afterResult += term;
error = (afterResult - beforeResult) / afterResult;
if (error < 0) error * -1;
error *= 100;
beforeResult = afterResult;
term = 1;
i++;
}
return beforeResult;
}
double fact (double num) {
int i, j;
double total = 1;
for (i = 2; i <= num; i++) {
total = total * i;
}
return total;
}
When computing exponent via Taylor serie
exp(x) = 1 + x / 1 + x**2/2! + ... + x**n/n!
you don't want any factorials, please, notice that if n-1th term is
t(n-1) = x**(n-1)/(n-1)!
then
t(n) = x**n/n! = t(n-1) * x / n;
That's why all you have to implement is:
double calculateEx(double x) {
double term = 1.0;
double result = term;
/*
the only trick is that term can be positive as well as negative;
we should either use abs in any implementation or putr two conditions
*/
for (int n = 1; term > 0.001 || term < -0.001; ++n) {
term = term * x / n;
result += term;
}
return result;
}
OK, as I wrote in a comment above, I'd use <math.h> if at all possible, but since you asked the question:
To make it work with negative numbers, if x is negative, consider what happens if you negate it.
You can get rid of the factorial function by storing a table of factorials. You won't need that many elements.
I've been following the guide my prof gave us, but I just can't find where I went wrong. I've also been going through some other questions about implementing the Taylor Series in C.
Just assume that RaiseTo(raise a number to the power of x) is there.
double factorial (int n)
{
int fact = 1,
flag;
for (flag = 1; flag <= n; flag++)
{
fact *= flag;
}
return flag;
}
double sine (double rad)
{
int flag_2,
plusOrMinus2 = 0; //1 for plus, 0 for minus
double sin,
val2 = rad,
radRaisedToX2,
terms;
terms = NUMBER_OF_TERMS; //10 terms
for (flag_2 = 1; flag_2 <= 2 * terms; flag_2 += 2)
{
radRaisedToX2 = RaiseTo(rad, flag_2);
if (plusOrMinus2 == 0)
{
val2 -= radRaisedToX2/factorial(flag_2);
plusOrMinus2++; //Add the next number
}
else
{
val2 += radRaisedToX2/factorial(flag_2);
plusOrMinus2--; //Subtract the next number
}
}
sin = val2;
return sin;
}
int main()
{
int degree;
scanf("%d", °ree);
double rad, cosx, sinx;
rad = degree * PI / 180.00;
//cosx = cosine (rad);
sinx = sine (rad);
printf("%lf \n%lf", rad, sinx);
}
So during the loop, I get the rad^x, divide it by the factorial of the odd number series starting from 1, then add or subtract it depending on what's needed, but when I run the program, I get outputs way above one, and we all know that the limits of sin(x) are 1 and -1, I'd really like to know where I went wrong so I could improve, sorry if it's a pretty bad question.
Anything over 12! is larger than can fit into a 32-bit int, so such values will overflow and therefore won't return what you expect.
Instead of computing the full factorial each time, take a look at each term in the sequence relative to the previous one. For any given term, the next one is -((x*x)/(flag_2*(flag_2-1)) times the previous one. So start with a term of x, then multiply by that factor for each successive term.
There's also a trick to calculating the result to the precision of a double without knowing how many terms you need. I'll leave that as an exercise to the reader.
In the function factorial you are doing an int multiply before assigned to the double return value of the function. Factorials can easily break the int range, such as 20! = 2432902008176640000.
You also returned the wrong variable - the loop counter!
Please change the local variable to double, as
double factorial (int n)
{
double fact = 1;
int flag;
for (flag = 1; flag <= n; flag++)
{
fact *= flag;
}
return fact; // it was the wrong variable, and wrong type
}
Also there is not even any need for a factorial calculation. Note that each term of the series multiplies the previous term by rad and divides by the term number - with a change of sign.
Another fairly naive, 5-minute approach involves computing a look-up table that contains the first 20 or so factorials, i.e 1! .. 20! This requires very little memory and can increase speed over the 'each-time' computation method. A further optimization can easily be realized in the function that pre-computes the factorials, taking advantage of the relationship each has to the previous one.
An approach that efficiently eliminated branching (if X do Y else do Z) in the loops of the two trig functions would provide yet more speed again.
C code
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
const int nMaxTerms=20;
double factorials[nMaxTerms];
double factorial(int n)
{
if (n==1)
return 1;
else
return (double)n * factorial(n - 1.0);
}
void precalcFactorials()
{
for (int i=1; i<nMaxTerms+1; i++)
{
factorials[i-1] = factorial(i);
}
}
/*
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! .......
*/
double taylorSine(double rads)
{
double result = rads;
for (int curTerm=1; curTerm<=(nMaxTerms/2)-1; curTerm++)
{
double curTermValue = pow(rads, (curTerm*2)+1);
curTermValue /= factorials[ curTerm*2 ];
if (curTerm & 0x01)
result -= curTermValue;
else
result += curTermValue;
}
return result;
}
/*
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! .......
*/
double taylorCos(double rads)
{
double result = 1.0;
for (int curTerm=1; curTerm<=(nMaxTerms/2)-1; curTerm++)
{
double curTermValue = pow(rads, (curTerm*2) );
curTermValue /= factorials[ (curTerm*2) - 1 ];
if (curTerm & 0x01)
result -= curTermValue;
else
result += curTermValue;
}
return result;
}
int main()
{
precalcFactorials();
printf("Math sin(0.5) = %f\n", sin(0.5));
printf("taylorSin(0.5) = %f\n", taylorSine(0.5));
printf("Math cos(0.5) = %f\n", cos(0.5));
printf("taylorCos(0.5) = %f\n", taylorCos(0.5));
return 0;
}
output
Math sin(0.5) = 0.479426
taylorSin(0.5) = 0.479426
Math cos(0.5) = 0.877583
taylorCos(0.5) = 0.877583
Javascript
Implemented in javascript, the code produces seemingly identical results (I didn't test very much) to the inbuilt Math library when summing just 7 terms in the sin/cos functions.
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
console.log('starting');
for (var i=1; i<21; i++)
factorials[i-1] = factorial(i);
console.log('calculated');
console.log(" Math.cos(0.5) = " + Math.cos(0.5));
console.log("taylorCos(0.5) = " + taylorCos(0.5));
console.log('-');
console.log(" Math.sin(0.5) = " + Math.sin(0.5));
console.log("taylorSine(0.5) = " + taylorSine(0.5));
}
var factorials = [];
function factorial(n)
{
if (n==1)
return 1;
else
return n * factorial(n-1);
}
/*
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! .......
*/
function taylorSine(x)
{
var result = x;
for (var curTerm=1; curTerm<=7; curTerm++)
{
var curTermValue = Math.pow(x, (curTerm*2)+1);
curTermValue /= factorials[ curTerm*2 ];
if (curTerm & 0x01)
result -= curTermValue;
else
result += curTermValue;
}
return result;
}
/*
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! .......
*/
function taylorCos(x)
{
var result = 1.0;
for (var curTerm=1; curTerm<=7; curTerm++)
{
var curTermValue = Math.pow(x, (curTerm*2));
curTermValue /= factorials[ (curTerm*2)-1 ];
if (curTerm & 0x01)
result -= curTermValue;
else
result += curTermValue;
}
return result;
}
#include <stdio.h>
double pi = 3.141592653589;
int numberOfTerms = 5;
int factorial(int n)
{
if(n > 1)
return n * factorial(n - 1);
else
return 1;
}
double DegreesToRadian( double degrees )
{
return degrees * pi / 180;
}
void cosine(double cos){
int x = 0;
double ans = 1;
int exponent = 2;
int isPlus = 0;
for(x; x < numberOfTerms - 1; x++){
if(isPlus == 0){
ans -= (pow(cos, exponent))/factorial(exponent);
exponent += 2;
isPlus = 1;
}else{
ans += (pow(cos, exponent))/factorial(exponent);
exponent += 2;
isPlus = 0;
}
}
printf ("%.12f \t", ans);
}
void sine(double sin){
int x = 0;
double ans = sin;
int exponent = 3;
int isPlus = 0;
for(x; x < numberOfTerms - 1; x++){
if(isPlus == 0){
ans -= (pow(sin, exponent))/factorial(exponent);
exponent += 2;
isPlus = 1;
}else{
ans += (pow(sin, exponent))/factorial(exponent);
exponent += 2;
isPlus = 0;
}
}
printf ("%.12f \n", ans);
}
int main()
{
double j = -180.00;
printf(" ");
printf("\n\n");
for (j; j <= 180; j += 5){
printf("%.2f \t", j);
printf( "%.12f \t", DegreesToRadian(j));
cosine(DegreesToRadian(j));
sine(DegreesToRadian(j));
}
return 0;
}
I'm using Taylor Series to find the sin and cosine of a number but when I change the numberOfTerms to 10 or 15 it becomes inaccurate(waaaaaaaaayy off), what do I need to change to make it accurate? (Yeah my functions are not optimal lel)
I get a [Warning] incompatible implicit declaration of built-in function 'pow' if that matters.
Let us assume you keep the value of numberOfTerms as 10. Then, in the cosine and sine functions, in the for loop, you are incrementing exponent by 2 every time. And, you are using the factorial of exponent in the denominator.
If the loop runs 9 times, the value for exponent would increase as 2, 4, 6, 8, 10, 12, 14, 16, 18.
We know that 14! = 87178291200. But a signed int (which is used to return the result of the factorial function) can hold a positive value up to 2147483647. There occurs an overflow.
I suggest you use double (or even unsigned long long) for the return type and the parameter of the factorial function. But do not try to compute factorials of large numbers as they would not fit in any data type in C.
Also, since you have not defined pow function yourself, I think you are missing a #include<math.h> at the top.
Another suggestion, define pi as a symbolic constant rather than a global variable.
The implicit declaration of pow returns an int, but the actual definition returns double, the code will interpret the double an an int by bit pattern resulting in an entirely incorrect value - not just the integer part of the double.
I have a logical problem in my code, maybe it is caused by overflowing but I can't solve this on my own, so I would be thankful if anyone can help me.
In the following piece of code, I have implemented the function taylor_log(), which can count "n" iterations of taylor polynomial. In the void function I am looking for number of iterations (*limit) which is enough to count a logarithm with desired accuracy compared to log function from .
The thing is that sometimes UINT_MAX is not enough iterations to get the desired accuracy and at this point I want to let the user know that the number of needed iterations is higher than UINT_MAX. But my code don't work, for example for x = 1e+280, eps = 623. It just counts, counts and never give result.
TaylorPolynomial
double taylor_log(double x, unsigned int n){
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; i <= n; i++)
{
f_sum *= (x - 1) / x;
sum += f_sum / i;
}
return sum;
}
void guessIt(double x, double eps, unsigned int *limit){
*limit = 10;
double real_log = log(x);
double t_log = taylor_log(x, *limit);
while(myabs(real_log - t_log) > eps)
{
if (*limit == UINT_MAX)
{
*limit = 0;
break;
}
if (*limit >= UINT_MAX/2)
{
*limit = UINT_MAX;
t_log = taylor_log(x, *limit);
}
else
{
*limit = (*limit) *2;
t_log = taylor_log(x, *limit);
}
}
}
EDIT: Ok guys, thanks for your reactions so far. I have changed my code to this:
if (*limit == UINT_MAX-1)
{
*limit = 0;
break;
}
if (*limit >= UINT_MAX/2)
{
*limit = UINT_MAX-1;
t_log = taylor_log(x, *limit);
}
but it still doesn't work correctly, I have set printf to the beggining of taylor_log() function to see the value of "n" and its (..., 671088640, 1342177280, 2684354560, 5, 4, 3, 2, 2, 1, 2013265920, ...). Don't understand it..
This code below assigns the limit to UINT_MAX
if (*limit >= UINT_MAX/2)
{
*limit = UINT_MAX;
t_log = taylor_log(x, *limit);
}
And your for loop is defined like this:
for (unsigned int i = 1; i <= n; i++)
i will ALWAYS be less than or equal to UINT_MAX because there is never going to be a value of i that is greater than UINT_MAX. Because that's the largest value i could ever be. So there is certainly overflow and your loop exit condition is never met. i rolls over to zero and the process repeats indefinitely.
You should change your loop condition to i < n or change your limit to UINT_MAX - 1.
[Edit]
OP coded correctly but must insure a limited range (0.5 < x < 2.0 ?)
Below is a code version that self determines when to stop. Iteration count goes high near x near 0.5 and 2.0. The iteration count needed goes into the millions. Such the alternative coded far below.
double taylor_logA(double x) {
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; ; i++) {
f_sum *= (x - 1) / x;
double sum_before = sum;
sum += f_sum / i;
if (sum_before == sum) {
printf("%d\n", i);
break;
}
}
return sum;
}
Wrongalternative implementation of the series: Ref
Sample alternative - it converges faster.
double taylor_log2(double x, unsigned int n) {
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; i <= n; i++) {
f_sum *= (x - 1) / 1; // / 1 (or remove)
if (i & 1) sum += f_sum / i;
else sum -= f_sum / i; // subtract even terms
}
return sum;
}
A reasonable number of terms will converge as needed.
Alternatively, continue until terms are too small (maybe 50 or so)
double taylor_log3(double x) {
double f_sum = 1.0;
double sum = 0.0;
for (unsigned int i = 1; ; i++) {
double sum_before = sum;
f_sum *= x - 1;
if (i & 1) sum += f_sum / i;
else sum -= f_sum / i;
if (sum_before == sum) {
printf("%d\n", i);
break;
}
}
return sum;
}
Other improvements possible. example see More efficient series
First, using std::numeric_limits<unsigned int>::max() will make your code more c++-ish than c-ish. Second, you can use the integral type unsigned long long and std::numeric_limits<unsigned long long>::max() for the limit, which is pretty mush the limit for an integral type. If you want a higher limit, you may use long double. floating points also allows you to use infinity with std::numeric_limits<double>::infinity() note that infinity work with double, float and long double.
If neither of these types provide you the precision you need, look at boost::multiprecision
First of all, the Taylor series for the logarithm function only converges for values of 0 < x < 2, so it's quite possible that the eps precision is never hit.
Secondly, are you sure that it loops forever, instead of hitting the *limit >= UINT_MAX/2 after a very long time?
OP is using the series well outside its usable range of 0.5 x < 2.0 with calls like taylor_log(1e280, n)
Even within the range, x values near the limits of 0.5 and 2.0 converge very slowly needing millions+ of iterations. A precise log() will not result. Best to use the 2x range about 1.0.
Create a wrapper function to call the original function in its sweet range of sqrt(2)/2 < x < sqrt(2). Converges, worst case, with about 40 iterations.
#define SQRT_0_5 0.70710678118654752440084436210485
#define LN2 0.69314718055994530941723212145818
// Valid over the range (0...DBL_MAX]
double taylor_logB(double x, unsigned int n) {
int expo;
double signif = frexp(x, &expo);
if (signif < SQRT_0_5) {
signif *= 2;
expo--;
}
double y = taylor_log(signif,n);
y += expo*LN2;
return y;
}