Calibrating in C program - c

Problem: To measure the volume of liquid in the tank, a depth gauge (measuring stick) can be used. It is inserted into an opening at the top and the level of liquid on the gauge can be used to determine the amount of liquid in the tank.
The tank has width w, height h and length len (in m). In the example output shown below, we take w=8, h=4 and len=7. Your programs should work for any values of w, h and len, not just these specific values.
We look at inserting a measuring stick that is already calibrated in units of 10 centimeters. This measuring gauge can be inserted into an opening at the top of the tank and used to measure the depth of the liquid in the tank.
Your task will be to write a C program to produce a table of values showing the volume of liquid in the tank for each of the points on the gauge.
The output of your program (for the example above) should look like:
Depth 10 cm : Volume 1.188814 cubic meters
Depth 20 cm : Volume 3.336448 cubic meters
Depth 30 cm : Volume 5.992683 cubic meters
. . .
Depth 380 cm : Volume 172.547399 cubic meters
Depth 390 cm : Volume 174.657114 cubic meters
Depth 400 cm : Volume 175.743037 cubic meters
Methodology:
If the tank has width W and height H (in centimeters), the focal radii of the cross section are A = W/2 and B = H/2. Then the equation of the ellipse is:
X^2/A^2 + Y^2/B^2 = 1
To find the volume at given depth you should compute the cross-sectional area of the tank for each given depth using a numerical integration
algorithm such as the trapezoidal method.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
double WIDTH;
double HEIGHT;
double LENGTH;
//Function: y in terms of x
typedef double (*DFD) (double);
double f (double x)
{
double a = HEIGHT / 2.0;
double b = WIDTH / 2.0;
double y = (b / a) * sqrt (a * a - x * x);
return y;
}
//Integrating the function -> Area
double trapezoidal_int (DFD f ,double a, double b, int n){
double x, dx, sum=0.0;
int i=0;
dx = (b-a)/ n;
sum = (f(a) + f(b))/2;
for (i=1, x = a + dx; i < n; i++, x += dx)
sum += f(x);
return 2.0 * sum * dx;
}
int main ()
{
int h_cm;
printf ("Enter Width of the tank (in m):\n");
scanf ("%lf",&WIDTH);
printf ("Enter Height of the tank (in m):\n");
scanf ("%lf",&HEIGHT);
printf ("Enter Length of the tank(in m):\n");
scanf ("%lf",&LENGTH);
for (h_cm = 0; h_cm <= HEIGHT * 100; h_cm += 10) {
double h = h_cm / 100.0;
double area = trapezoidal_int (&f, HEIGHT / 2 - h, HEIGHT / 2, 100);
double volume = area * LENGTH;
printf ("Depth %d cm: Volume %.6lf cubic metres\n",
h_cm, volume);
}
return 0;
}

There are a few mistakes here and there. First, let's use global variables for the dimensions of the tank so that function f() can use them:
double WIDTH;
double HEIGHT;
double LENGTH;
You function f() had the height and width reversed:
double f (double x)
{
double a = HEIGHT / 2.0;
double b = WIDTH / 2.0;
double y = (b / a) * sqrt (a * a - x * x);
return y;
}
The doubling of the value of the integral, which is necessary to measure both sides of the major axis, should be done in main() and not in trapezoidal_int(). It is bad practice to have a function that does not do what it's name suggests.
The bounds of integration were also wrong:
int main ()
{
int h_cm;
WIDTH = 8.0;
HEIGHT = 4.0;
LENGTH = 7.0;
for (h_cm = 0; h_cm <= HEIGHT * 100; h_cm += 10) {
double h = h_cm / 100.0;
double area = 2.0 * trapezoidal_int (&f, HEIGHT / 2 - h,
HEIGHT / 2, 100);
double volume = area * LENGTH;
printf ("Depth %d cm: Volume %.6lf cubic metres\n",
h_cm, volume);
}
return 0;
}

Related

Specifying float or double yet getting int value

#include <stdio.h>
int diameter_fn(int r)
{
return (2 * r);
}
void circumference_fn(int r)
{
float pie = 22 / 7;
float circum = (2 * pie * r);
printf(", Circumference = %f", circum);
}
void area_fn(int r)
{
float pie = 22 / 7;
float area = (22 * r * r / 7);
printf(" & the Area = %f", area);
}
int main()
{
printf("\nName = Parth_Agrawal & UID = 22BCS10924\n");
int radius;
printf("Enter the Radius of Circle:\t\t");
scanf("%d", &radius);
printf("\nDiameter = %d", diameter_fn(radius));
circumference_fn(radius);
area_fn(radius);
return 0;
}
I want to calculate Circumference, diameter and area of circle using functions yet I get non-perfect Circumference and area values.
I already tried replacing the float with double, %f with %lf etc but I am always getting the Circumference and area in xxx.0000 format,I.e, similar to Int converted to float format.
Like the area for 4 unit radius is 50.27 but it is giving me 50.000000 which is too much annoying.
This is the Result I am getting
whereas this is the Result which I should get
... but it is giving me 50.000000 ...
OP is using integer math in many places where floating point math is needed.
void circumference_fn(int r) {
float pie = 22 / 7; // Integer math!!
float circum = (2 * pie * r);
printf(", Circumference = %f", circum);
}
void area_fn(int r) {
float pie = 22 / 7; // Integer math!! pie not used
float area = (22 * r * r / 7);// Integer math!!
printf(" & the Area = %f", area);
}
Instead use FP math.
Scant reason to use float. Use double as the default FP type.
Rather than approximate π with 22/7, use a more precise value.
#define PIE 3.1415926535897932384626433832795
void circumference_fn(int r) {
double circum = (2 * PIE * r);
printf(", Circumference = %f", circum);
}
void area_fn(int r) {
double area = PIE * r * r;
printf(" & the Area = %f", area);
}
Other
All three functions should take a double argument and return a double.
Use "%g" for printing. It is more informative with wee values and less verbose with large ones.
#Shawn is right: you are using integer math to calculate Pi. You should #include <math.h> and use M_PI instead of trying to calculate it yourself.

Taylor Series in C (problem with sin(240) and sin(300))

#include <stdio.h>
#include <math.h>
const int TERMS = 7;
const float PI = 3.14159265358979;
int fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += pow(-1, n) * pow(rad, (2 * n) + 1)/ fact((2 * n) + 1);
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
The code above was implemented to compute sine and cosine using Taylor series.
I tried testing the code and it works fine for sine(120).
I am getting wrong answers for sine(240) and sine(300).
Can anyone help me find out why those errors occur?
You should calculate the functions in the first quadrant only [0, pi/2). Exploit the properties of the functions to get the values for other angles. For instance, for values of x between [pi/2, pi), sin(x) can be calculated by sin(pi - x).
The sine of 120 degrees, which is 40 past 90 degrees, is the same as 50 degrees: 40 degrees before 90. Sine starts at 0, then rises toward 1 at 90 degrees, and then falls again in a mirror image to zero at 180.
The negative sine values from pi to 2pi are just -sin(x - pi). I'd handle everything by this recursive definition:
sin(x):
cases x of:
[0, pi/2) -> calculate (Taylor or whatever)
[pi/2, pi) -> sin(pi - x)
[pi/2, 2pi) -> -sin(x - pi)
< 0 -> sin(-x)
>= 2pi -> sin(fmod(x, 2pi)) // floating-point remainder
A similar approach for cos, using identity cases appropriate for it.
The key point is:
TERMS is too small to have proper precision. And if you increase TERMS, you have to change fact implementation as it will likely overflow when working with int.
I would use a sign to toggle the -1 power instead of pow(-1,n) overkill.
Then use double for the value of PI to avoid losing too many decimals
Then for high values, you should increase the number of terms (this is the main issue). using long long for your factorial method or you get overflow. I set 10 and get proper results:
#include <stdio.h>
#include <math.h>
const int TERMS = 10;
const double PI = 3.14159265358979;
long long fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double powd(double x,int n) {
return n<= 0 ? 1 : x * powd(x,n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += sign * powd(rad, (2 * n) + 1)/ fact((2 * n) + 1);
sign = -sign;
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += sign * powd(rad, 2 * n) / fact(2 * n);
sign = -sign;
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
result:
240
sine(240)= -0.866026
cosine(240)= -0.500001
Notes:
my recusive implementation of pow using successive multiplications is probably not needed, since we're dealing with floating point. It introduces accumulation error if n is big.
fact could be using floating point to allow bigger numbers and better precision. Actually I suggested long long but it would be better not to assume that the size will be enough. Better use standard type like int64_t for that.
fact and pow results could be pre-computed/hardcoded as well. This would save computation time.
const double TERMS = 14;
const double PI = 3.14159265358979;
double fact(double n) {return n <= 0.0 ? 1 : n * fact(n - 1);}
double sine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad, 2 * PI);
double sin = 0;
for (double n = 0; n < TERMS; n++)
sin += pow(-1, n) * pow(rad, (2 * n) + 1) / fact((2 * n) + 1);
return sin;
}
double cosine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad,2*PI);
double cos = 0;
for (double n = 0; n < TERMS; n++)
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
return cos;
}
int main()
{
printf("sine(240)= %lf\n", sine(240));
printf("cosine(300)= %lf\n",cosine(300));
}

Improvement to my Mandelbrot set code

I have the following Mandelbrot set code in C. I am doing the calculation and creating a .ppm file for the final fractal image. The point is that my fractal image is upside down, meaning it is rotated by 90 degrees. You can check it by executing my code:
./mandel > test.ppm
On the other hand, I also want to change the colours. I want to achieve this fractal image:
My final issue is that my code doesn't check the running time of my code. I have the code for this part too, but when code execution finishes it doesn't print the running time. If someone can make the appropriate changes to my code and help me achieve this fractal image, and make elapsed time displayed I would be glad.
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
void color(int red, int green, int blue)
{
fputc((char)red, stdout);
fputc((char)green, stdout);
fputc((char)blue, stdout);
}
int main(int argc, char *argv[])
{
int w = 600, h = 400, x, y;
//each iteration, it calculates: newz = oldz*oldz + p, where p is the current pixel, and oldz stars at the origin
double pr, pi; //real and imaginary part of the pixel p
double newRe, newIm, oldRe, oldIm; //real and imaginary parts of new and old z
double zoom = 1, moveX = -0.5, moveY = 0; //you can change these to zoom and change position
int maxIterations = 1000;//after how much iterations the function should stop
clock_t begin, end;
double time_spent;
printf("P6\n# CREATOR: E.T / mandel program\n");
printf("%d %d\n255\n",w,h);
begin = clock();
//loop through every pixel
for(x = 0; x < w; x++)
for(y = 0; y < h; y++)
{
//calculate the initial real and imaginary part of z, based on the pixel location and zoom and position values
pr = 1.5 * (x - w / 2) / (0.5 * zoom * w) + moveX;
pi = (y - h / 2) / (0.5 * zoom * h) + moveY;
newRe = newIm = oldRe = oldIm = 0; //these should start at 0,0
//"i" will represent the number of iterations
int i;
//start the iteration process
for(i = 0; i < maxIterations; i++)
{
//remember value of previous iteration
oldRe = newRe;
oldIm = newIm;
//the actual iteration, the real and imaginary part are calculated
newRe = oldRe * oldRe - oldIm * oldIm + pr;
newIm = 2 * oldRe * oldIm + pi;
//if the point is outside the circle with radius 2: stop
if((newRe * newRe + newIm * newIm) > 4) break;
}
color(i % 256, 255, 255 * (i < maxIterations));
}
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Elapsed time: %.2lf seconds.\n", time_spent);
return 0;
}
Part 1:
You need to swap the order of your loops to:
for(y = 0; y < h; y++)
for(x = 0; x < w; x++)
That will give you the correctly oriented fractal.
Part 2:
To get the time to print out, you should print it to stderr since you are printing the ppm output to stdout:
fprintf(stderr, "Elapsed time: %.2lf seconds.\n", time_spent);
Part 3:
To get a continuous smooth coloring, you need to use the Normalized Iteration Count method or something similar. Here is a replacement for your coloring section that gives you something similar to what you desire:
if(i == maxIterations)
color(0, 0, 0); // black
else
{
double z = sqrt(newRe * newRe + newIm * newIm);
int brightness = 256. * log2(1.75 + i - log2(log2(z))) / log2(double(maxIterations));
color(brightness, brightness, 255);
}
It isn't quite there because I kind of did a simple approximate implementation of the Normalized Iteration Count method.
It isn't a fully continuous coloring, but it is kind of close.

How to generate a set of points that are equidistant from each other and lie on a circle

I am trying to generate an array of n points that are equidistant from each other and lie on a circle in C. Basically, I need to be able to pass a function the number of points that I would like to generate and get back an array of points.
It's been a really long time since I've done C/C++, so I've had a stab at this more to see how I got on with it, but here's some code that will calculate the points for you. (It's a VS2010 console application)
// CirclePoints.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "math.h"
int _tmain()
{
int points = 8;
double radius = 100;
double step = ((3.14159265 * 2) / points);
double x, y, current = 0;
for (int i = 0; i < points; i++)
{
x = sin(current) * radius;
y = cos(current) * radius;
printf("point: %d x:%lf y:%lf\n", i, x, y);
current += step;
}
return 0;
}
Try something like this:
void make_circle(float *output, size_t num, float radius)
{
size_t i;
for(i = 0; i < num; i++)
{
const float angle = 2 * M_PI * i / num;
*output++ = radius * cos(angle);
*output++ = radius * sin(angle);
}
}
This is untested, there might be an off-by-one hiding in the angle step calculation but it should be close.
This assumes I understood the question correctly, of course.
UPDATE: Redid the angle computation to not be incrementing, to reduce float precision loss due to repeated addition.
Here's a solution, somewhat optimized, untested. Error can accumulate, but using double rather than float probably more than makes up for it except with extremely large values of n.
void make_circle(double *dest, size_t n, double r)
{
double x0 = cos(2*M_PI/n), y0 = sin(2*M_PI/n), x=x0, y=y0, tmp;
for (;;) {
*dest++ = r*x;
*dest++ = r*y;
if (!--n) break;
tmp = x*x0 - y*y0;
y = x*y0 + y*x0;
x = tmp;
}
}
You have to solve this in c language:
In an x-y Cartesian coordinate system, the circle with centre coordinates (a, b) and radius r is the set of all points (x, y) such that
(x - a)^2 + (y - b)^2 = r^2
Here's a javascript implementation that also takes an optional center point.
function circlePoints (radius, numPoints, centerX, centerY) {
centerX = centerX || 0;
centerY = centerY || 0;
var
step = (Math.PI * 2) / numPoints,
current = 0,
i = 0,
results = [],
x, y;
for (; i < numPoints; i += 1) {
x = centerX + Math.sin(current) * radius;
y = centerY + Math.cos(current) * radius;
results.push([x,y]);
console.log('point %d # x:%d, y:%d', i, x, y);
current += step;
}
return results;
}

Filling a polygon

I created this function that draws a simple polygon with n number of vertexes:
void polygon (int n)
{
double pI = 3.141592653589;
double area = min(width / 2, height / 2);
int X = 0, Y = area - 1;
double offset = Y;
int lastx, lasty;
double radius = sqrt(X * X + Y * Y);
double quadrant = atan2(Y, X);
int i;
for (i = 1; i <= n; i++)
{
lastx = X; lasty = Y;
quadrant = quadrant + pI * 2.0 / n;
X = round((double)radius * cos(quadrant));
Y = round((double)radius * sin(quadrant));
setpen((i * 255) / n, 0, 0, 0.0, 1); // r(interval) g b, a, size
moveto(offset + lastx, offset + lasty); // Moves line offset
lineto(offset + X, offset + Y); // Draws a line from offset
}
}
How can I fill it with a solid color?
I have no idea how can I modify my code in order to draw it filled.
The common approach to fill shapes is to find where the edges of the polygon cross either each x or each y coordinate. Usually, y coordinates are used, so that the filling can be done using horizontal lines. (On framebuffer devices like VGA, horizontal lines are faster than vertical lines, because they use consecutive memory/framebuffer addresses.)
In that vein,
void fill_regular_polygon(int center_x, int center_y, int vertices, int radius)
{
const double a = 2.0 * 3.14159265358979323846 / (double)vertices;
int i = 1;
int y, px, py, nx, ny;
if (vertices < 3 || radius < 1)
return;
px = 0;
py = -radius;
nx = (int)(0.5 + radius * sin(a));
ny = (int)(0.5 - radius * cos(a));
y = -radius;
while (y <= ny || ny > py) {
const int x = px + (nx - px) * (y - py) / (ny - py);
if (center_y + y >= 0 && center_y + y < height) {
if (center_x - x >= 0)
moveto(center_x - x, center_y + y);
else
moveto(0, center_y + y);
if (center_x + x < width)
lineto(center_x + x, center_y + y);
else
lineto(width - 1, center_y + y);
}
y++;
while (y > ny) {
if (nx < 0)
return;
i++;
px = nx;
py = ny;
nx = (int)(0.5 + radius * sin(a * (double)i));
ny = (int)(0.5 - radius * cos(a * (double)i));
}
}
}
Note that I only tested the above with a simple SVG generator, and compared the drawn lines to the polygon. Seems to work correctly, but use at your own risk; no guarantees.
For general shapes, use your favourite search engine to look for "polygon filling" algorithms. For example, this, this, this, and this.
There are 2 different ways to implement a solution:
Scan-line
Starting at the coordinate that is at the top (smallest y value), continue to scan down line by line (incrementing y) and see which edges intersect the line.
For convex polygons you find 2 points, (x1,y) and (x2,y). Simply draw a line between those on each scan-line.
For concave polygons this can also be a multiple of 2. Simply draw lines between each pair. After one pair, go to the next 2 coordinates. This will create a filled/unfilled/filled/unfilled pattern on that scan line which resolves to the correct overall solution.
In case you have self-intersecting polygons, you would also find coordinates that are equal to some of the polygon points, and you have to filter them out. After that, you should be in one of the cases above.
If you filtered out the polygon points during scan-lining, don't forget to draw them as well.
Flood-fill
The other option is to use flood-filling. It has to perform more work evaluating the border cases at every step per pixel, so this tends to turn out as a slower version. The idea is to pick a seed point within the polygon, and basically recursively extend up/down/left/right pixel by pixel until you hit a border.
The algorithm has to read and write the entire surface of the polygon, and does not cross self-intersection points. There can be considerable stack-buildup (for naive implementations at least) for large surfaces, and the reduced flexibility you have for the border condition is pixel-based (e.g. flooding into gaps when other things are drawn on top of the polygon). In this sense, this is not a mathematically correct solution, but it works well for many applications.
The most efficient solution is by decomposing the regular polygon in trapezoids (and one or two triangles).
By symmetry, the vertexes are vertically aligned and it is an easy matter to find the limiting abscissas (X + R cos(2πn/N) and X + R cos(2π(+1)N)).
You also have the ordinates (Y + R sin(2πn/N) and Y + R sin(2π(+1)N)) and it suffices to interpolate linearly between two vertexes by Y = Y0 + (Y1 - Y0) (X - X0) / (X1 - X0).
Filling in horizontal runs is a little more complex, as the vertices may not be aligned horizontally and there are more trapezoids.
Anyway, it seems that I / solved / this myself again, when not relying on assistance (or any attempt for it)
void polygon (int n)
{
double pI = 3.141592653589;
double area = min(width / 2, height / 2);
int X = 0, Y = area - 1;
double offset = Y;
int lastx, lasty;
while(Y-->0) {
double radius = sqrt(X * X + Y * Y);
double quadrant = atan2(Y, X);
int i;
for (i = 1; i <= n; i++)
{
lastx = X; lasty = Y;
quadrant = quadrant + pI * 2.0 / n;
X = round((double)radius * cos(quadrant));
Y = round((double)radius * sin(quadrant));
//setpen((i * 255) / n, 0, 0, 0.0, 1);
setpen(255, 0, 0, 0.0, 1); // just red
moveto(offset + lastx, offset + lasty);
lineto(offset + X, offset + Y);
} }
}
As you can see, it isn't very complex, which means it might not be the most efficient solution either.. but it is close enough.
It decrements radius and fills it by virtue of its smaller version with smaller radius.
On that way, precision plays an important role and the higher n is the less accuracy it will be filled with.

Resources