Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h2>Last version</h2> <pre><code>#include &lt;stdio.h&gt; // for input/output. #include &lt;math.h&gt; // for mathmatic functions (log, pow, etc.) // Values #define MAXELM 1000 // Array size #define MINVAL 0.1 // Minimum x value #define MAXVAL 1.9 // Maximum x value #define EXPVAR 1.4 // Exponent which makes the variation non linear. If set to 1, the variation will be linear. #define ACRTPT (MINVAL + MAXVAL)/2 // Accurate point. This value is used to know where to compute with maximum accuracy. Can be set to a fixed value. // Behavior #define STRICT 0 // if TRUE: Return -1 instead of the floored (or closest if out of range) offset when (x) hasn't been calculated for this value. #define PNTALL 0 // if TRUE: Print all the calculated values. #define ASKFOR 1 // if TRUE: Ask for a x value then print the calculated ln value for it. // Global vars double results[MAXELM]; // Array to store computed values. // Func: offset to var conversion double getvar(int offset) { double x = (double)MINVAL + ((double)MAXVAL - (double)MINVAL) * (double)offset / (double)MAXELM; if(x &gt;= (double)ACRTPT) x = pow(x - (double)ACRTPT, (double)EXPVAR) + (double)ACRTPT; else x = -pow((double)ACRTPT - x, (double)EXPVAR) + (double)ACRTPT; // This ^ is the equation used when NONLIN = 1; to have a non linear repartition. Feel free to change it. The inverse equation is in `int getoffset(double)`. return x; } // Func: var to offset conversion int getoffset(double var) { double x = var; if(x &gt;= (double)ACRTPT) x = pow(x - (double)ACRTPT, 1.0/(double)EXPVAR) + (double)ACRTPT; else x = -pow((double)ACRTPT - x, 1.0/(double)EXPVAR) + (double)ACRTPT; // This ^ is the equation used when NONLIN = 1; to calculate offset with a non linear repartition. Feel free to change it (but it must be the inverse of the one in // `double getvar(int)` for this to work.). These equations are tied, so you cannot modify one without modifying the other. They are here because // `pow(negative, non-integer)` always returns `-nan` instead of the correct value. This 'trick' uses the fact that (-x)^(1/3) == -(x^(1/3)) to cicumvent the // limitation. int offset = (x - (double)MINVAL) * (double)MAXELM / ((double)MAXVAL - (double)MINVAL); #if STRICT if(getvar(offset) != var) return -1; return (offset &lt; 0)?-1:(offset &gt; (MAXELM - 1))?-1:offset; #else return (offset &lt; 0)?0:(offset &gt; (MAXELM - 1))?MAXELM - 1:offset; #endif } // Func: main. int main(int argc, char* argv[]) { int offset; for(offset = 0; offset &lt; MAXELM; offset++) results[offset] = log(getvar(offset)); #if PNTALL for(offset = 0; offset &lt; MAXELM; offset++) { printf("[log(%lf) = %lf] ", getvar(offset), results[offset]); if(!((offset + 1) % 6)) printf("\n"); } printf("\n"); #endif #if ASKFOR double x; printf("log(x) for x = "); scanf("%lf", &amp;x); if((offset = getoffset(x)) &lt; 0) printf("ERROR: Value for x = %lf hasn't been calculated\n", x); else printf("results[%d]: log(%lf) = %lf\n", offset, getvar(offset), results[offset]); #endif return 0; } </code></pre> <p>Last versions's characteristics:</p> <ul> <li>Uses a fixed size array.</li> <li>Computes ONLY the stored values (won't calculate multiple values for one array cell).</li> <li>Uses functions to get offset from value and value from offset, so you don't have to store the values of which the <code>log</code> has been calculated.</li> </ul> <p>Advantages over the last version:</p> <ul> <li>Does not use <code>cbrt</code>, uses <code>pow</code> instead.</li> <li>Allows to specify the growth of calculus variable at compilation time. (So the values are more or less grouped around the accurate point (<code>ACRTPT</code>))</li> </ul> <hr> <h2>Third version</h2> <pre><code>#include &lt;stdio.h&gt; // for input/output. #include &lt;math.h&gt; // for mathmatic functions (log, pow, etc.) // Values #define MAXELM 1000 // Array size #define MINVAL 0.1 // Minimum x value #define MAXVAL 1.9 // Maximum x value #define ACRTPT (MINVAL + MAXVAL)/2 // Accurate point. This value is used to know where to compute with maximum accuracy. Can be set to a fixed value. // Behavior #define NONLIN 1 // if TRUE: Calculate log values with a quadratic distribution instead of linear distribution. #define STRICT 1 // if TRUE: Return -1 instead of the floored (or closest if out of range) offset when (x) hasn't been calculated for this value. #define PNTALL 0 // if TRUE: Print all the calculated values. #define ASKFOR 1 // if TRUE: Ask for a x value then print the calculated ln value for it. // Global vars double results[MAXELM]; // Array to store computed values. // Func: offset to var conversion double getvar(int offset) { double x = (double)MINVAL + ((double)MAXVAL - (double)MINVAL) * (double)offset / (double)MAXELM; #if NONLIN x = pow((x - ACRTPT), 3) + ACRTPT; // This ^ is the equation used when NONLIN = 1; to have a non linear repartition. Feel free to change it. The inverse equation is in `int getoffset(double)`. #endif return x; } // Func: var to offset conversion int getoffset(double var) { #if NONLIN int offset = (( cbrt(var - ACRTPT) + ACRTPT // This ^ is the equation used when NONLIN = 1; to calculate offset with a non linear repartition. Feel free to change it (but it must be the inverse of the one in // `double getvar(int)` for this to work.) ) - (double)MINVAL) * (double)MAXELM / ((double)MAXVAL - (double)MINVAL); #else int offset = (var - (double)MINVAL) * (double)MAXELM / ((double)MAXVAL - (double)MINVAL); #endif #if STRICT if(getvar(offset) != var) return -1; return (offset &lt; 0)?-1:(offset &gt; (MAXELM - 1))?-1:offset; #else return (offset &lt; 0)?0:(offset &gt; (MAXELM - 1))?MAXELM - 1:offset; #endif } // Func: main. int main(int argc, char* argv[]) { int offset; for(offset = 0; offset &lt; MAXELM; offset++) results[offset] = log(getvar(offset)); #if PNTALL for(offset = 0; offset &lt; MAXELM; offset++) { printf("[log(%lf) = %lf] ", getvar(offset), results[offset]); if(!((offset + 1) % 6)) printf("\n"); } printf("\n"); #endif #if ASKFOR double x; printf("log(x) for x = "); scanf("%lf", &amp;x); if((offset = getoffset(x)) &lt; 0) printf("ERROR: Value for x = %lf hasn't been calculated\n", x); else printf("results[%d]: log(%lf) = %lf\n", offset, getvar(offset), results[offset]); #endif return 0; } </code></pre> <p>This version is cleaner and easier to maintain than the previous ones. If you need anything else, please leave a comment.</p> <p>You can configure its behavior using the macros at the top of the file.</p> <p>Caracteristics:</p> <ul> <li>Uses a fixed size array.</li> <li>Computes ONLY the stored values (won't calculate multiple values for one array cell).</li> <li>Uses functions to get offset from value and value from offset, so you don't have to store the values of which the <code>log</code> has been calculated.</li> </ul> <hr> <h2>Second version</h2> <p>Well, here is my second solution. See below it for the original comment.</p> <pre><code>#include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;math.h&gt; #define MIN_INC 0.001 // This is the minimum increment. If its set to 0, when tmp will be equal to avg, it will never leave this state, since INC_MUL * (tmp - avg)^2 will be 0. #define INC_MUL 0.2 // This is a number which influences the precision you will get. The smaller it is, the more precise you will be, and the greater will be your result array cardinality. typedef struct { double offset; double value; // value = log(offset). Since the results are not linarly widespread, this is pretty important. } logCalc; // Here, we need to use a pointer on a logCalc pointer, since we want to actually SET the address of the logCalc pointer, not the address of one of its copies. int MyLogCreate(logCalc** arr, double min, double max) { if((*arr) != NULL) return 0; unsigned int i = 0; double tmp, avg = (max + min) / 2.0; for( ; min &lt; avg; min += (INC_MUL * ((avg - min) * (avg - min)) + MIN_INC)) { (*arr) = (logCalc*)realloc((*arr), sizeof(logCalc) * (i + 1)); (*arr)[i].offset = min; (*arr)[i++].value = log(min); } for(tmp = avg ; tmp &lt; max; tmp += (INC_MUL * ((tmp - avg) * (tmp - avg)) + MIN_INC)) { (*arr) = (logCalc*)realloc((*arr), sizeof(logCalc) * (i + 1)); (*arr)[i].offset = tmp; (*arr)[i++].value = log(tmp); } return i; } int main(int argc, char** argv) { logCalc *myloglut = NULL; unsigned int i, t = MyLogCreate(&amp;myloglut, .1, 1.9); for(i = 0; i &lt; (t-1); i++) { printf("[log(%lf) = %lf], ", myloglut[i].offset, myloglut[i].value); if(!((i+1)%6)) // Change 6 to what's best for your terminal $COLUMNS printf("\n"); } printf("\n"); free(myloglut); return 0; } </code></pre> <hr> <h2>Original comment</h2> <p>The linearity of your calculation comes from the fact that you're using a linear increment. On each iteration of your for loop, you increment <code>exp</code> by <code>(2.0 - 0.1) / MAXLOG</code>.</p> <p>To get more precise values around 0, you will need:</p> <ol> <li>To define a larger range - a larger array - (to be able to store more values around 0)</li> <li>To use a non-linear increment. This increment will probably be dependent on <code>i</code> (or on <code>exp</code>, depending on how you do it), so you know precisely the "offset" of the number you are trying to calculate (and the amount you need to increment <code>exp</code> with). Of course, you will calculate more results around 0.</li> </ol> <p>Here is my current implementation of it:</p> <pre><code>#include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;math.h&gt; #define CALCULATE_UNTIL 2.0 #define PRECISE_UNTIL 1.0 typedef struct { double offset; double value; } logCalc; logCalc *myloglut = NULL; int MyLogCreate() { double exp = 0.1; int i; for (i = 0; exp &lt;= CALCULATE_UNTIL; exp += (exp &lt; PRECISE_UNTIL)?0.0001898:0.001898) { myloglut = realloc(myloglut, sizeof(logCalc) * (i + 1)); myloglut[i].offset = exp; myloglut[i++].value = (i == 4780)?0:log(exp); } return i; // So you know how big the array is. Don't forget to free(myloglut); at the end of your code. } int main(int argc, char** argv) { int i, t = MyLogCreate(); for(i = 0; i &lt; t; i++) { printf("[log(%lf) = %lf], ", myloglut[i].offset, myloglut[i].value); if(!(i%6)) // For formatting purposes. printf("\n"); } printf("\n"); free(myloglut); return 0; } </code></pre> <p>I've created a new type in order to store the value of exp too, which could be useful for knowing what value the result is the log of.</p> <p><em>Update:</em> I'm not sure about what you want to do. Do you want to be precise around log(x) = 0 or around x = 0? On the first case, I might have to re-write the code again for it to work as you want. Also, do you want the results to be more precise at it gets close to 0, or do you want the results to be more precise in a given range (as it is now)?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload