0.1 increment in a While Loop (C Programming) - c

I am in an introductory C programming class. Our latest project has us writing code to tabulate x and sqrt(x) values from 1-10 with a 0.1 step using a while loop. When I try to do the 0.1 increment, however, nothing is added to the starting integer 1 and the program runs in an infinite loop. I'll post the code below. Other than it not doing the step, the program runs fine (and works with other increments like 1, etc.). How do I resolve this?
#include <stdio.h>
#include <math.h>
int main(void)
{
int x=1;
double sq_rt;
printf("Square Root Table: \n");
printf("Value of X Square Root of X\n");
while (x <= 10)
{
sq_rt = sqrt (x);
printf("%6i %20f \n", x, sq_rt);
x += 1e-1;
}
return 0;
}

An int type will only allow you to store whole numbers (i.e. -2, -1, 0, 1, 2 etc). To store numbers with a decimal point, you'll need a double precision (or double) type. Change the first line of main() to:
double x = 1.0;
If you try to add 1e-1 to an int, it will convert it to an int first - the type of x - which when truncated will end up being zero, so you'll never actually add anything to x.

The line in your program which reads
x += 1e-1;
is performing operations equivalent to
x = (int)(((double)x) + 0.1);
In other words, x is first converted to a double, then 0.1 is added to it, resulting in 1.1. This value is then converted to int, resulting in a value of 1, which is assigned to x.
The fix is to change the type of x to a floating point type such as float or double.
Share and enjoy.

the following code is a suggestion on how to perform the desired algorithm.
#include <stdio.h>
#include <math.h>
// define the magic numbers, don't embed them in the code
#define UPPER_LIMIT (10.0)
#define STEP_SIZE (0.1)
int main(void)
{
double x=1.0;
double sq_rt;
printf("Square Root Table: \n");
printf("Value of X Square Root of X\n");
// due to ambiguities in 'real' values,
// this loop will iterate approx. 90 times.
while( x < UPPER_LIMIT )
{
sq_rt = sqrt (x);
// display the two double values
// note: long float conversion values
// because the underlying numbers are double
// note: blanks for alignment with column headers
printf("%9.6lf %16.13lf \n", x, sq_rt);
// increase base value by increment of 0.1
x += STEP_SIZE;
} // end while
return 0;
} // end function: main

Related

Why is my method for this question wrong: Write a function power (int a, int b), to calculate the value of a raised to b using while loop in c

Note: I am a total beginner at c and this question was given in my university assignment.
Question: Write a function power (int a, int b), to calculate the value of a raised to b using while loop in C.
I used the following code for the hackerrank question given above:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int power(int a, int b);
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int a, b, result;
scanf("%d %d", &a, &b);
result = power(a, b);
printf("%d", result);
return 0;
}
int power(int x, int y) {
int z = x;
while (y > 1) {
x *= z;
y--;
}
return x;
}
But this problem gave me errors in some of the test cases. This was easily fixed by just changing z=x to z=1, x*=z to z*=x and return (x) to return (z).
But I do not understand why my initial code was wrong.
Using z=1 instead of z=x fixes the result for y=0.[1]
The other two changes just serve to make the code clearer, but provide no function difference.
The results are still wrong for y<0 even with this fix. However, the function is not very useful for y<0 since the best it could do is to round to 0 or 1, usually 0.
Your code:
int power(int x,int y)
{
int z=x;
while (y>1)
{
x*=z;
y--;
}
return(x);
}
Will start multiplying already with x, when none of the y was yet used for multiplication. On the other hand, using 1 would result in 1 without any multiplication and requires the first decrement of y to become x. This matches the required result of 1 for x to the power of 0.
Using z*=x repeatedly multiplies with x, which results as expected in x to the power of y (when starting with 1).
Doing x*=z results in repeated multiplication with z (which was x in your code), which seems right. But because of the need to start with 1 (see above) AND to keep the original value of x, a second variable is needed. Keeping the original value of x and storing the changing result in the new variable makes more sense than the other way round.
Returning the variable which contains the result is obvious, it just is the other variable after the change above.
Negative values of y seem to be irrelevant four your assignment. If they also need to be covered think of the result of e.g. x to the power of 2, then "undo" that, by subtracting 2 again from the exponent by dividing twice by x again. You are back at x to the power of 0. Then "undo" the same way again, i.e. divide twice again by x. The result is then x to the power of -2, i.e. 1/(x*x).

How to convert an float with unknown decimals into an integer without data loss? [duplicate]

I want to write code that, if I input a decimal number like 612.216, I can print it as a 612216 (actually convert it to integer). However, the program changes my number to something like 2162160000000000000000001 and I don't what to do about it.
This is my code:
#include <stdio.h>
#include <math.h>
int main() {
long double x;
scanf_s("%Lf", &x);
while (floor(x)!=x)
x = x * 10;
printf("%Lf", x);
return 0;}
How about this:
#include <stdio.h>
int main() {
double number = 612.216;
char number_as_string[20];
snprintf(number_as_string,"%lf", number);
for(int i = 0; number_as_string[i] != '\0'; i++)
if(number_as_string[i] != '.')
printf("%c", number_as_string[i]);
return 0;
}
The downside is the statically allocated array. You can use snprintf to convert the double into an array of chars.
The floating point representation isn't exact so there is a very very small error in any floating point number. You could try something like this pseudocode,
while ((x - floor(x) > 0.0000000000000000001)
x *= 10;
Your math library might define a better number to use like FLT_MIN or some such ;)
The problem with your floor(x)!=x check is that it doesn't take into account any inaccuracy in the representation of the input long double number. (In the example given, this causes an 'extra' 0.0000000000000000000001 to be added to the actual value.) See Is floating point math broken? for more information on such inaccuracies inherent in any representation of floating-point numbers.
To fix this in your code, you can compare the difference between floor(x) and x to a given 'tolerance' - if it's less than that, consider the loop finished. You can use a value derived from the LDBL_EPSILON constant as a typical value for that 'tolerance', though you may like to experiment with different values.
Here is a possible code solution:
#include <stdio.h>
#include <math.h>
#include <float.h> // For the LDBL_EPSILON definition
int main()
{
long double x;
scanf_s("%Lf", &x);
while ((x - floor(x)) > (LDBL_EPSILON * x * 10)) // Try changing the "10" value!
x = x * 10;
printf("%.0Lf", x); // Add the ".0" to remove the trailing ".000000" in the output
return 0;
}
long double can store many finite values exactly. There are all of the form:
+/- some_integer * 2some_exponent
Since "612.216" is not represent-able like that (0.216 cannot be expressed as a binary fraction like 0.25 can), a nearby long double value was used like ~612.2160000000000000253...
Also, OP's repeated use of x = x * 10; adds small rounding errors and does not pose a reasonable conversion limit.
A alternative approach uses LDBL_DIG (the number of significant decimal digits that round trip from decimal text to long double to decimal text unchanged) and to print the double to a buffer. Let *printf() do the heavy lifting of converting a double to the best decimal text.
#include <float.h>
#include <stdio.h>
// To print up to the LDBL_DIG most significant digits w/o trailing zeros:
void print_sig_digits(long double x) {
// - d . ddd....ddd e - expo \0
char buf[1 + 1 + 1 + (LDBL_DIG-1) + 1 + 1 + 8 +1];
#define e_OFFSET (1 + 1 + 1 + (LDBL_DIG-1))
// Print using exponential format
snprintf(buf, sizeof buf, "%+.*Le", LDBL_DIG, x);
buf[e_OFFSET] = '\0'; // End string at 'e'
for (int i = e_OFFSET - 1; buf[i] == '0'; i--) {
buf[i] = '\0'; // Lop off trailing '0'
}
buf[2] = buf[1]; // Copy first digit over '.'
printf("%s\n", &buf[2]);
}
int main(void) {
printf("LDBL_DIG: %d\n", LDBL_DIG);
print_sig_digits( 612.216L);
print_sig_digits( 1.0L/7);
print_sig_digits( 0.000123L);
return 0;
}
Output
LDBL_DIG: 18
612216
142857142857142857
123

"Domain error" from sqrt() when drawing an ellipse?

The program to draw an ellipse using polynominal algoritm.
#include< graphics.h>
#include< stdio.h>
#include< math.h>
#include< conio.h>
void main() {
int gd=DETECT,gm;
float a,b,h,k;
float x,xend,y;
clrscr();
initgraph(&gd,&gm,"C:\\TC\\BGI");
printf("Enter the semi major axis and semi minor axis:\n");
scanf("%f%f",&a,&b);
printf("\nEnter the center coordinates, (h,k):");
scanf("%f%f",&h,&k);
xend=a;
for(x=0;x<=xend;x = x+0.1){
y=b*sqrt(1-(x*x)/(a));
putpixel(x+h,y+k,RED);
putpixel(-x+h,y+k,RED);
putpixel(-x+h,-y+k,RED);
putpixel(x+h,-y+k,RED);
}
getch();
//closegraph();
}
/*
output
Enter the semi major axis and semi minor axis:
200 130
Enter the center coordinates, (h,k):
200 230
*/
The output of the program shows
sqrt: Domain error
How to solve this error.
There are several issues here:
The domain error results from passing an illegal argument to sqrt. The sqrt function takes a non-negative argument and returns the non-negative square root. It is a good idea to check the argument of the square root, the discriminant, before calling sqrt unless you can be absolutely sure that the argument is valid.
In your loop, you accumulate floating-point numbers. Such additions are inaccurate, especially if you do many accumulations. It is better to control your loop with integers and then calculate a floating-point number from these integers.
Your formula isn't correct. An ellipsis is described by
(x/a)² + (y/b)² = 1
You are missing one a in the denominator here. (It may be better to use a normalised rnning variable.)
Putting all this together:
#include <stdio.h>
#include <math.h>
int main()
{
float a = 200.0f;
float b = 130.0f;
int i;
int n = 50;
for (i = 0; i <= n; i++) {
float c = 1.0f * i / n; // normalised x
float x = a * c; // actual x
float discr = 1.0f - c*c; // calc. discriminat separately ...
float y = (discr <= 0) ? 0 // ... so we can check it
: b * sqrtf(discr);
printf("%20.12f%20.12f\n", x, y);
}
return 0;
}
(The third point is the most important, of course. When you deal with discrete pixels, it might also be questionable to increment your running variable by fractions of 1.0.)
Your problem is here:
for(x=0;x<=xend;x = x+0.1){
y=b*sqrt(1-(x*x)/(a));
X is 0 at the start and 1 - (x * x) / (a) can be negative if the division results in a value less than 1. 1 - (0 * 0) / (a) will be 1 in most cases (a == 0 is a special case). So, you pass a negative value to sqrt, which expects positive values. In reality one can calculate the square root of a negative number as well if the domain of the result is the set of Complex numbers, but, unfortunately sqrt is not applicable for that purpose.

taylor series with error at most 10^-3

I'm trying to calculate the the taylor series of cos(x) with error at most 10^-3 and for all x ∈ [-pi/4, pi/4], that means my error needs to be less than 0.001. I can modify the x +=in the for loop to have different result. I tried several numbers but it never turns to an error less than 0.001.
#include <stdio.h>
#include <math.h>
float cosine(float x, int j)
{
float val = 1;
for (int k = j - 1; k >= 0; --k)
val = 1 - x*x/(2*k+2)/(2*k+1)*val;
return val;
}
int main( void )
{
for( double x = 0; x <= PI/4; x += 0.9999 )
{
if(cosine(x, 2) <= 0.001)
{
printf("cos(x) : %10g %10g %10g\n", x, cos(x), cosine(x, 2));
}
printf("cos(x) : %10g %10g %10g\n", x, cos(x), cosine(x, 2));
}
return 0;
}
I'm also doing this for e^x too. For this part, x must in [-2,2] .
float exponential(int n, float x)
{
float sum = 1.0f; // initialize sum of series
for (int i = n - 1; i > 0; --i )
sum = 1 + x * sum / i;
return sum;
}
int main( void )
{
// change the number of x in for loop so you can have different range
for( float x = -2.0f; x <= 2.0f; x += 1.587 )
{
// change the frist parameter to have different n value
if(exponential(5, x) <= 0.001)
{
printf("e^x = %f\n", exponential(5, x));
}
printf("e^x = %f\n", exponential(5, x));
}
return 0;
}
But whenever I changed the number of terms in the for loop, it always have an error that is greater than 1. How am I suppose to change it to have errors less than 10^-3?
Thanks!
My understanding is that to increase precision, you would need to consider more terms in the Taylor series. For example, consider what happens when
you attempt to calculate e(1) by a Taylor series.
$e(x) = \sum\limits_{n=0}^{\infty} frac{x^n}{n!}$
we can consider the first few terms in the expansion of e(1):
n value of nth term sum
0 x^0/0! = 1 1
1 x^1/1! = 1 2
2 x^2/2! = 0.5 2.5
3 x^3/3! = 0.16667 2.66667
4 x^4/4! = 0.04167 2.70834
You should notice two things, first that as we add more terms we are getting closer to the exact value of e(1), also that the difference between consecutive sums are getting smaller.
So, an implementation of e(x) could be written as:
#include <stdbool.h>
#include <stdio.h>
#include <math.h>
typedef float (*term)(int, int);
float evalSum(int, int, int, term);
float expTerm(int, int);
int fact(int);
int mypow(int, int);
bool sgn(float);
const int maxTerm = 10; // number of terms to evaluate in series
const float epsilon = 0.001; // the accepted error
int main(void)
{
// change these values to modify the range and increment
float start = -2;
float end = 2;
float inc = 1;
for(int x = start; x <= end; x += inc)
{
float value = 0;
float prev = 0;
for(int ndx = 0; ndx < maxTerm; ndx++)
{
value = evalSum(0, ndx, x, expTerm);
float diff = fabs(value-prev);
if((sgn(value) && sgn(prev)) && (diff < epsilon))
break;
else
prev = value;
}
printf("the approximate value of exp(%d) is %f\n", x, value);
}
return 0;
}
I've used as a guess that we will not need to use more then ten terms in the expansion to get to the desired precision, thus the inner for loop is where we loop over values of n in the range [0,10].
Also, we have several lines dedicated to checking if we reach the required precision. First I calculate the absolute value of the difference between the current evaluation and the previous evaluation, and take the absolute difference. Checking if the difference is less than our epsilon value (1E-3) is on of the criteria to exit the loop early. I also needed to check that the sign of of the current and the previous values were the same due to some fluctuation in calculating the value of e(-1), that is what the first clause in the conditional is doing.
float evalSum(int start, int end, int val, term fnct)
{
float sum = 0;
for(int n = start; n <= end; n++)
{
sum += fnct(n, val);
}
return sum;
}
This is a utility function that I wrote to evaluate the first n-terms of a series. start is the starting value (which is this code always 0), and end is the ending value. The final parameter is a pointer to a function that represents how to calculate a given term. In this code, fnct can be a pointer to any function that takes to integer parameters and returns a float.
float expTerm(int n, int x)
{
return (float)mypow(x,n)/(float)fact(n);
}
Buried down in this one-line function is where most of the work happens. This function represents the closed form of a Taylor expansion for e(n). Looking carefully at the above, you should be able to see that we are calculating $\fract{x^n}{n!}$ for a given value of x and n. As a hint, for doing the cosine part you would need to create a function to evaluate the closed for a term in the Taylor expansion of cos. This is given by $(-1)^n\fact{x^{2n}}{(2n)!}$.
int fact(int n)
{
if(0 == n)
return 1; // by defination
else if(1 == n)
return 1;
else
return n*fact(n-1);
}
This is just a standard implementation of the factorial function. Nothing special to see here.
int mypow(int base, int exp)
{
int result = 1;
while(exp)
{
if(exp&1) // b&1 quick check for odd power
{
result *= base;
}
exp >>=1; // exp >>= 1 quick division by 2
base *= base;
}
return result;
}
A custom function for doing exponentiation. We certainly could have used the version from <math.h>, but because I knew we would only be doing integer powers we could write an optimized version. Hint: in doing cosine you probably will need to use the version from <math.h> to work with floating point bases.
bool sgn(float x)
{
if(x < 0) return false;
else return true;
}
An incredibly simple function to determine the sign of a floating point value, returning true is positive and false otherwise.
This code was compiled on my Ubuntu-14.04 using gcc version 4.8.4:
******#crossbow:~/personal/projects$ gcc -std=c99 -pedantic -Wall series.c -o series
******#crossbow:~/personal/projects$ ./series
the approximate value of exp(-2) is 0.135097
the approximate value of exp(-1) is 0.367857
the approximate value of exp(0) is 1.000000
the approximate value of exp(1) is 2.718254
the approximate value of exp(2) is 7.388713
The expected values, as given by using bc are:
******#crossbow:~$ bc -l
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
e(-2)
.13533528323661269189
e(-1)
.36787944117144232159
e(0)
1.00000000000000000000
e(1)
2.71828182845904523536
e(2)
7.38905609893065022723
As you can see, the values are well within the tolerances that you requests. I leave it as an exercise to do the cosine part.
Hope this helps,
-T
exp and cos have power series that converge everywhere on the real line. For any bounded interval, e.g. [-pi/4, pi/4] or [-2, 2], the power series converge not just pointwise, but uniformly to exp and cos.
Pointwise convergence means that for any x in the region, and any epsilon > 0, you can pick a large enough N so that the approximation you get from the first N terms of the taylor series is within epsilon of the true value. However, with pointwise convergence, the N may be small for some x's and large for others, and since there are infinitely many x's there may be no finite N that accommodates them all. For some functions that really is what happens sometimes.
Uniform convergence means that for any epsilon > 0, you can pick a large enough N so that the approximation is within epsilon for EVERY x in the region. That's the kind of approximation that you are looking for, and you are guaranteed that that's the kind of convergence that you have.
In principle you could look at one of the proofs that exp, cos are uniformly convergent on any finite domain, sit down and say "what if we take epsilon = .001, and the regions to be ...", and compute some finite bound on N using a pen and paper. However most of these proofs will use at some steps some estimates that aren't sharp, so the value of N that you compute will be larger than necessary -- maybe a lot larger. It would be simpler to just implement it for N being a variable, then check the values using a for-loop like you did in your code, and see how large you have to make it so that the error is less than .001 everywhere.
So, I can't tell what the right value of N you need to pick is, but the math guarantees that if you keep trying larger values eventually you will find one that works.

Casting not working well in C

programming C using xcode, here's the f
#include <stdio.h>
int multiply (int x, int y) {
return x * y;
}
int main()
{
float result = (float) multiply (0.2, 0.5);
printf("the result is %f", result);
}
I don't get the right value, I get 0.0000 !! I did the casting but I don't know whats wrong.
Your program multiplies 0 by 0.
multiply takes two int parameters, so your 0.2 and 0.5 are implicitly converted to int before making the call. That truncates both to 0.
Your typecast doesn't do anything in this program, since the return value of multiply (which is an int) will get implicitly converted during the assignment to result anyway.
You need to change the definition of multiply (or add a floating-point version and call that) if you want this program to work correctly.
The multiply () input arguments are int:
int multiply (int x, int y) {
and you have passed float as input arguments:
multiply (0.2, 0.5);
Hi there is a basic problem. As the numbers you are multiplying are floats but you are passing these into the function multiply as int's hence being rounded to 1 and 0.
This should work
#include <stdio.h>
int multiply (float x, float y) {
return x * y;
}
int main()
{
float result = (float) multiply (0.2, 0.5);
printf("the result is %f", result);
}

Resources