I'm trying to learn C from the C Programming Language book, in there, one of the exercises is to make a Fahrenheit to Celsius converter.
my code following the books style and instructions is:
#include <stdio.h>
int main() {
float fhr;
for (fhr = 0; fhr <= 300; fhr += 20)
printf("%3.1f %6.1f\n", fhr, (5.0/9.0)*(fhr-32));
}
It says in the book:
I just want to know if making a celsius variable and then calling it in the printf function as an argument is better or doing it this way is better, from both human readability and more importantly if it makes any difference to the compiler (I.e. makes the program run any faster or slower.)
Thanks.
Making a variable and then passing it to the printf would surely improve the readability.
From the compiler point of view there's no actual difference. It doesn't affect runtime performances in any way. This is especially true when it comes down to the internal optimizations the compiler carries out.
From a compiler standpoint it potentially does have an impact. Depending on the compiler, it might see that the variable is only used once and "inline" the value anyway. Many may not, which would cause a hit to the overall performance. That being said, the performance hit would be inconsequential.
As for readability, storing it as its own variable would be easier to look at, and maintain later. Although for a small program like this, the difference is also pretty inconsequential; however, it might start making a difference in larger programs, especially if the value is going to be used more than once.
#include <stdio.h>
int main()
{
float fhr;
for (fhr = 0; fhr <= 300; fhr += 20)
{
float celsius = (5.0/9.0)*(fhr-32);
printf("%3.1f %6.1f\n", fhr, celsius);
}
}
You might also want to consider using a function, to abstract out how this value is determined. Again, this does create a hit to performance, and isn't necessary for such a small program, but would provide access to a way to determine the value from more places in the program. This would mean you would not need to rely on passing the value around, or having the variable within scope:
float fahrenheit_to_celsius(float fhr)
{
return 5.0 / 9.0 * (fhr - 32)
}
int main()
{
float fhr;
for (fhr = 0; fhr <= 300; fhr += 20)
{
float celsius = fahrenheit_to_celsius(fhr);
printf("%3.1f %6.1f\n", fhr, celsius);
}
}
You can also use a function for it, it won't be slower, and it's way better for readability (in my opinion)!
#include <stdio.h>
double fhr_to_cls(double fhr)
{
return ((5.0 / 9.0) * ( fhr - 32));
}
int main()
{
double fhr;
for (fhr = 0; fhr <= 300; fhr += 20)
printf("%3.1f %6.1f\n", fhr, fhr_to_cls(fhr));
}
regarding:
for (fhr = 0; fhr <= 300; fhr += 20)
printf("%3.1f %6.1f\n", fhr, (5.0/9.0)*(fhr-32));
the 0 and 300 and 20 and 32 are all integers that the code is trying to stuff into a float
the 5.0and9/0aredoubles`
to correct all the above, Suggest:
for ( fhr = 0.0f; fhr <= 300.0f; fhr += 20.0f )
printf("%3.1f %6.1f\n", fhr, (5.0f / 9.0f )*(fhr-32.0f));
Related
We are doing C Programming in school and we have to calculate the cosine of a number with use of the "Taylor series" (https://en.wikipedia.org/wiki/Taylor_series). I know C programming but that what we have to do has not really much to do with programming itself more than being good in math.
If you put in your calculator cos(50) it's 0.6427.... That's what we have to do in C. There is the cos() function in math.h but that's not actually the cosine. I am overwhelmed with this and don't really know what we have to do. It should look something like this:
#include <stdio.h>
#include <conio.h>
#include <math.h>
int fac(int n);
double meincosinus(double x);
void main() {
double x;
double y;
int i;
printf("geben sie eine zahl ein\n");
scanf_s("%lf", &x);
y = meincosinus(x);
printf_s("cos(%lf)=%lf\n", x, y);
y = sin(x);
printf_s("cos(%lf)=%lf\n", x, y);
scanf_s("%d", &i);
printf_s("%d\n", i);
_getch();
}
int fac(int n) {
int prod = 1;
int i;
for (i = 1; i <= n; i++)
{
prod *= i;
}
return prod;
}
double meincosinus(double x)
{
double erg = 0;
int n;
for (n = 0; n <= x; n++)
{
x = fac(n);
erg += pow(-1, n) * pow(x, (2 * n)) / fac(2 * n);
}
return erg;
}
This code runs but the output is wrong.
Not an answer (but, well, I am a teacher myself, I am not gonna make your homework :)). But a few questions you should ask yourself and that might help you
Why are you comparing your Taylor computation of cosinus with the "real" sinus? Shouldn't y=sin(x) be y=cos(x), for a pertinent comparison?
why are you doing this: x = fac(n);? You are overwriting your x argument to "meinconsinus". You can't expect meincosinus(50) to really compute cos(50) if the first thing you do is overwriting that "50" with something else (namely n!).
also, why this for (n = 0; n <= x; n++). You know the Taylor formula better that I do (since you are studying it right now). It sure not supposed to stop after x iterations. x is rarely even an integer. It is supposed to be very small anyway. And could even be negative. So, question you've to ask yourself is, how many iterations (up to which term of the series) you want to compute. It is a rather arbitrary choice, since from Taylor point of view, answer is ∞. But on a computer, after a while it is no use to add extremely small numbers
Since I am mentioning the fact that x is supposed to be small: you can't compute cos(50) that way with a Taylor formula. You could compute cos(0.1) or even cos(1) maybe, with enough iterations. But 50 is not a small enough number. Plus, 50ⁿ will be very quickly out of control in your loop. If you really want meincosinus to be able to handle any number, you have first to reduce x, using trigonometric rules: cos(x)=cos(x)-2π; cos(x)=-cos(x); cos(x)=sin(π/2-x); ... There are some better rules, but with those simple ones, you can have x in [0,π/4]. Since π/4<1, at least you don't have an explosive xⁿ.
Also, but that is an optimization, you don't really need to compute neither (-1)ⁿ with pow (just alternate a int sign variable, between -1 and 1 at each iteration), nor x²ⁿ (just multiply a double x2n=1 by x*x each iteration), nor fac(2n) (just multiply a f=1 variable by (n-1)×n, being careful with 0 case, at each iteration.
I would like to find all the primes within 100. Here is my codes.
// Find all the prime number within 100.
#include<stdio.h>
#include<math.h>
#include<stdbool.h>
int main() {
int i,n;
int j = 0;
for ( n = 2; n <= 100; ++n) {
bool isPrime = true;
for (i = 2; i <= sqrt(float(n)); ++i) {
if(n % i == 0) {
isPrime = false;
break;
}
}
if(isPrime) {
++j;
printf("%d is a prime number\n",n);
}
}
printf("The total number of prime number within 100 is %d\n",j);
return 0;
}
When compile it, there is one error.
prime.c:14:8: error: expected expression before ‘float’
m = float(n);
^
Could anyone help solve this problem? Thanks.
You're using the wrong syntax when casting (you're using one of C++'s many styles of casting, but for C there is only one way). Change:
sqrt(float(n))
to
sqrt((float)n)
Note however that sqrt takes a double, so strictly speaking this should be:
sqrt((double)n)
Note also that the cast is not necessary, and you can just write:
sqrt(n)
Change this
sqrt(float(n))
to this
sqrt((float)n)
You want to cast n to float.
You should use this function:
float sqrtf (float x);
which in C99 receives a float as an argument. Otherwise, it would be better to cast into double (if you use sqrt()).
sqrt-ref
What you have written:
float(n)
is like saying that float is a name of a function and you pass to it the parameter n.
Notice, that in your case, you don't need casting, since it's going to be performed automatically (to float if you use sqrtf() or to double if you use sqrt()).
Other notes, irrelevant with your syntax error.
Why not start the loop from 3 and increase the counter by two? If you think about it, this will faster and will produce the same results. If you want to test yourself, check my example here.
Also, what I had found pretty exciting when I was searching for primes, is the sieve of Eratosthene's (Κόσκινο του Ερατοσθένη) . Here is an example of it.
If you want to cast n to a float, use (float)n.
Just do:
sqrt(n);
You'll be having the exam same result as the casting for your case.
I am pretty flabbergasted as to why my code got stuck at the 16512th iteration even though it seemed to have no syntactical problems. Here is the code:
#include <stdio.h>
/*C version of Newton-Raphson method*/
float sqrt(float num);
main()
{
int i;
for (i = 1; i <= 100000; i++) {
printf("%d: %.3f\n", i, sqrt(i));
}
}
float sqrt(float num)
{
float guess, e, upperbound;
guess = 1;
e = 0.001;
do
{
upperbound = num / guess;
guess = (upperbound + guess) / 2;
} while (!(guess * guess >= num - e &&
guess * guess <= num + e));
return guess;
}
The code is supposed to find the square-root of all numbers from 1 to 100000 using the Newtonian-Raphson method, but nothing happened after the 16152th iteration. I am using the Developer Command Prompt for VS2012 to compile my scripts, if that information is of any help. Enlightenment will be gladly appreciated.
Honestly, when I posted mycomment, it was more a hunch than real knowledge. The algorithm was valid, so something must be making the while loop not terminate, and since you were properly using epsilons, we were hitting the limits from the float.
#PaulR's comments make it make more sense. The sqrt of 16512 is 128.499027233672... Float has fairly limited precision, so it wasn't getting anything within .001 of that number. It makes even more sense if you think of an even bigger number, e.g. sqrt(123455555.54321) (which is 11111.11111). Floating point precision won't necessarily even get you to the 11111, let alone 11111.111.
Changing to double "fixes" this, but just kicks the can down the road. Somewhere later on, we'd have the same precision issue, and this algorithm should work on any size number.
#mrbratch brings up the robust solution - define your tolerance as a percentage of the number. If you set e = num * 0.00001, your loop will always complete. Obviously, you can play with epsilon and tweak it to your satisfaction. And note, for big numbers, this can give you an integer that's not even the closest int to the right answer.
I can't speak for python, but I can confirm that javascript uses double precision.
As already explained in the comments, the problem is because you can't have that much precision (0.001) with any number. In particular, when the number is large enough, only the most important digits are saved. See the IEEE 754 standard if you want more information about how it works. http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Now, I'd recommend that you use a percentage of error for the tolerance:
float sqrt(float num)
{
float guess, e, upperbound;
guess = 1;
e = 0.001;
do
{
upperbound = num / guess;
guess = (upperbound + guess) / 2;
} while (!(guess * guess / num >= 1 - e &&
guess * guess / num <= 1 + e));
return guess;
}
Simple adjustment
Use relative Floating Point precision, not absolute.
There area as many FP representable numbers between 0.001 and 0.002 as between 1,000 and 2,000. So when calculating square root, the iterations should depend on the local relative error.
Do not use absolute error bounds like e = 0.001, but relative ones. Code then runs just fine.
// e = 0.001;
e = 0.001 * num;
[edit] I know see #Scott Mermelstein has a similar comment.
IMHO, the squaring causes loss of precision:
#include <stdio.h>
/*C version of Newton-Raphson method*/
float mysqrt(float num); /* avoid conflicts with built-in sqrt() if any */
int main(void)
{
int i;
for (i = 1; i <= 100000; i++) {
printf("%d: %.3f\n", i, (double)mysqrt(i)); /* cast to double, since printf() is varargs */
}
return 0;
}
float mysqrt(float num)
{
float newguess, e, oldguess;
e = 0.001;
newguess = 1.0;
do
{
oldguess = newguess;
newguess = (num/oldguess + newguess ) / 2;
/* compare tor the previous value; avoid squaring */
} while (newguess / oldguess > (1+e) || oldguess / newguess > (1+e) );
// } while (newguess < oldguess -e || newguess > oldguess +e); // "mostly works"
return newguess;
}
I've having trouble understanding what is the point of Symbolic Constants in C, I am sure there is a reason for them but I can't seem to see why you wouldn't just use a variable.
#include <stdio.h>
main()
{
float fahr, celsius;
float lower, upper, step;
lower = 0;
upper = 300;
step = 20;
printf("%s\t %s\n", "Fahrenheit", "Celsius");
fahr = lower;
while (fahr <= upper) {
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf("%3.0f\t\t %3.2f\n", fahr, celsius);
fahr = fahr + step;
}
}
Vs.
#include <stdio.h>
#define LOWER 0
#define UPPER 300
#define STEP 20
main()
{
float fahr, celsius;
printf("%s\t %s\n", "Fahrenheit", "Celsius");
fahr = LOWER;
while (fahr <= UPPER) {
celsius = (5.0 / 9.0) * (fahr - 32.0);
printf("%3.0f\t\t %3.2f\n", fahr, celsius);
fahr = fahr + STEP;
}
}
The (pre)compiler knows that symbolic constants won't change. It substitutes the value for the constant at compile time. If the "constant" is in a variable, it usually can't figure out that the variable will never change value. In consequence, the compiled code has to read the value from the memory allocated to the variable, which can make the program slightly slower and larger.
In C++, you can declare a variable to be const, which tells the compiler pretty much the same thing. This is why symbolic constants are frowned upon in C++.
Note, however, that in C (as opposed to C++) a const int variable is not a constant expression. Therefore, trying to do something like this:
const int a = 5;
int b[a] = {1, 2, 3, 4, 5};
will work in C++ but will get you a compilation error in C (assuming b was supposed to be a statically bound array).
One good example of why named constants are beneficial comes from the excellent book The Practice of Programming by Kernighan and Pike (1999).
§1.5 Magic Numbers
[...] This excerpt from a program to print a histogram of letter frequencies on a 24 by 80 cursor-addressed terminal is needlessly opaque because of a host of magic numbers:
...
fac = lim / 20;
if (fac < 1)
fac = 1;
for (i = 0, col = 0; i < 27; i++, j++) {
col += 3;
k = 21 - (let[i] / fac);
star = (let[i] == 0) ? ' ' : '*';
for (j = k; j < 22; j++)
draw(j, col, star);
}
draw(23, 2, ' ');
for (i = 'A'; i <= 'Z'; i++)
printf("%c ", i);
The code includes, among others, the numbers 20, 21, 22, 23, and 27. They're clearly related...or are they? In fact, there are only three numbers critical to this program: 24, the number of rows on the screen; 80, the number of columns; and 26, the number of letters in the alphabet. But none of these appears in the code, which makes the numbers that do even more magical.
By giving names to the principal numbers in the calculation, we can make the code easier to follow. We discover, for instance, that the number 3 comes from (80 - 1)/26 and that let should have 26 entries, not 27 (an off-by-one error perhaps caused by 1-indexed screen coordinates). Making a couple of other simplifications, this is the result:
enum {
MINROW = 1, /* top row */
MINCOL = 1, /* left edge */
MAXROW = 24, /* bottom edge (<=) */
MAXCOL = 80, /* right edge (<=) */
LABELROW = 1, /* position of labels */
NLET = 26, /* size of alphabet */
HEIGHT = (MAXROW - 4), /* height of bars */
WIDTH = (MAXCOL - 1)/NLET /* width of bars */
};
...
fac = (lim + HEIGHT - 1) / HEIGHT;
if (fac < 1)
fac = 1;
for (i = 0; i < NLET; i++) {
if (let[i] == 0)
continue;
for (j = HEIGHT - let[i]/fac; j < HEIGHT; j++)
draw(j+1 + LABELROW, (i+1)*WIDTH, '*');
}
draw(MAXROW-1, MINCOL+1, ' ');
for (i = 'A'; i <= 'Z'; i++)
printf("%c ", i);
Now it's clearer what the main loop does; it's an idiomatic loop from 0 to NLET, indicating that the loop is over the elements of the data. Also the calls to draw are easier to understand because words like MAXROW and MINCOL remind us of the order of arguments. Most important, it's now feasible to adapt the program to another size of display or different data. The numbers are demystified and so is the code.
The revised code doesn't actually use MINROW, which is interesting; one wonders which of the residual 1's should be MINROW.
Variables are scoped locally to the structure they're declared in. Of course you could use variables instead of symbolic constants, but that might take a lot of work. Consider an application that frequently uses radians. The symbolic constant #define TWO_PI 6.28 would be of high value to the programmer.
Jonathan made a good point in why you would want to use symbolic constants in C (and in any other programming language, BTW).
Syntactically, in C this is different from C++ and many other languages because it is much restrictive on how you may declare such symbolic constant. So-called const qualified variables don't account for this as they would in C++.
You may use a macro that is defined to any constant expression: integer or floating point constants, address expressions of static variables, and some forms of expression that you form from them. These are only treated by the preprocessing phase of the compiler and you'd have to be careful when you use complicated expressions in them.
Yo may declare integer constant expressions in form of integer enumeration constants such as in enum color { red = 0xFF00, green = 0x00FF00, blue = 0x0000FF };. They are only of some restricted use, because they are fixed to have type int. So you wouldn't cover all ranges of values that you'd might want with them.
You might also see integer character constants like 'a' or L'\x4567' as predefined symbolic constants, if you like. They translate an abstract concept (the character value "a") into the encoding of the executing platform (ASCII, EBDIC, whatever).
Jonathan provides an excellent example of the user of symbolic constants.
It is possible that the program used in the question is not the best one to answer this question. However, given the program, symbolic constants might make more sense in the following case:
#include <stdio.h>
#define FAHRENHEIT_TO_CELSIUS_CONVERSION_RATIO 5.0 / 9.0
#define FAHRENHEIT_TO_CELSIUS_ZERO_OFFSET 32.0
#define FAHRENHEIT_CELSIUS_COMMON_VALUE -40.0
#define UPPER 300.0
#define STEP 20.0
int main()
{
float fahr, celsius;
printf("%s\t %s\n", "Fahrenheit", "Celsius");
fahr = FAHRENHEIT_CELSIUS_COMMON_VALUE;
while (fahr <= UPPER) {
celsius = (fahr - FAHRENHEIT_TO_CELSIUS_ZERO_OFFSET) * (FAHRENHEIT_TO_CELSIUS_CONVERSION_RATIO);
printf("%3.0f\t\t %3.2f\n", fahr, celsius);
fahr = fahr + STEP;
}
}
Possibly this makes it easier to understand why symbolic constants might be useful.
The program includes stdio.h, a rather common include file. Let's look at some of the symbolic constants defined in stdlib.h. This version of stdio.h is from Xcode.
#define BUFSIZ 1024 /* size of buffer used by setbuf */
#define EOF (-1)
#define stdin __stdinp
#define stdout __stdoutp
#define stderr __stderrp
Let's also look at two symbolic constants defined in stdlib.h.
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
These values may vary from system to system but using them makes programming in C a lot easier and portable. The symbolic constants for stdin, stdout and stderr have been known to change in various operating system implementations.
Using BUFSIZ to define character arrays for C input buffers generally makes a lot of sense.
Using EXIT_FAILURE and EXIT_SUCCESS makes code much more readable, and I don't have to remember if 0 is failure or success.
Would anyone prefer (-1) over EOF?
Using a symbolic constant to define the size of arrays makes it much easier to change code in one place rather than having to search all over for a specific number embedded in the code.
So this program is supposed to estimate hourly temperatures throughout a day after being given the daily high, low and the hour which the low is expected. I am having problems calling up my functions inside the main function. I don't really understand how I am supposed to get specific information from the functions, and use it in place of a variable in my main function. I'm also having trouble grasping the idea of parameters and arguments. I'm sure I've messed up in more than one place here, but I'm mostly concerned about the functions right now. Any help would be appreciated.
#include <stdio.h>
#include <math.h>
#define PI 3.14159
double getFahrTemp(double high, double low, int hour);
double fahr2cels( double fahr );
double cels2kelv( double cels );
double fahr2rank( double fahr );
double getDailyHigh()
{
int high;
printf("Enter the daily high temperature <F>:\n");
scanf("%d",&high);
return high;
}
double getDailyLow()
{
int low;
printf("Enter the daily low temperature <F>:\n");
scanf("%d",&low);
return low;
}
int getLowHour()
{
int lowHour;
printf("Enter the time of the daily low temperature:\n");
scanf("%d",&lowHour);
return lowHour;
}
double getFahrTemp(double high, double low, int hour)
{
return (high-low)/2 * sin(2*PI/24 * hour + 3.0/2.0 * PI) + (high+low)/2;
}
double fahr2cels( double fahr )
{
double cels;
cels = fahr - 32 / 1.8;
}
double cels2kelv( double cels )
{
double kelv;
kelv = cels + 273;
}
double fahr2rank ( double fahr )
{
double rank;
rank = fahr + 459.67;
}
int main(getDailyHigh, getDailyLow, getLowHour, getFahrTemp)
{
int hour, time;
printf ("Temperature Scale Conversion Chart:\n")
printf ("TIME FAHR CELSIUS KELVIN RANKINE")
getDailyHigh();
getDailyLow();
getLowHour();
do
{
int time, hour=1;
time = (hour + lowHour) % 12;
getFahrTemp(getDailyHigh(), getDailyLow(), hour)
fahr2cels
cels2kelv
fahr2rank
printf ("%d:00 %2.2d %2.2d %3.2d %3.2d\n", time, fahr, cels, kelv, rank;
hour = hour++;
}
while (hour <= 24);
}
I don't really understand how I am
supposed to get specific information
from the functions, and use it in
place of a variable in my main
function. I'm also having trouble
grasping the idea of parameters and
arguments.
Do you understand the concept of a function in mathematics? For example, the equation to convert celcius to fahrenheit is:
°C = (°F − 32) × 5⁄9
One can write this as a mathematical function:
f(x) = (x - 32) × 5⁄9
The function f accepts a single argument called x and returns (x - 32) × 5⁄9. To "use" the function, you would write:
y = f(x)
Given a variable x, you can assign the result of function f to a variable y.
Once you understand this, you can easily see how it transfers to programming:
double fahr2cels(double f)
{
return (f - 32) * 5 / 9;
}
Calling the function even looks like "how math is done":
double celcius = fahr2cels(fahrenheit);
In the same way you can have multivariable functions in math, you can have functions that accept multiple parameters. You can even have functions that accept no parameters!
double getFahrTemp(double high, double low, int hour)
{
return (high-low)/2 * sin(2*PI/24 * hour + 3.0/2.0 * PI) + (high+low)/2;
}
The syntax for calling a function is fairly consistent:
// Call the function getFahrTemp(), passing three parameters.
// The variable fahrtemp receives the result of the function call.
double fahrtemp = getFahrTemp(high, low, hour);
There are some important differences I must take note of in this math analogy - functions in C can have side effects (they affect program state in some way outside the function). Also, parameters that you pass are always copied.
The problem is in this section:
fahr2cels
cels2kelv
fahr2rank
You need to pass the parameter specified:
degCel = fahr2cels(degF);
Some basic rules to help you understand:
All C statements end in a semicolon (;).
(none of your functions in the block cited had a semicolon at the end...)
Look to the function definition for information on what to pass
double fahr2cels( double fahr );
Says that the function takes 1 variable, which must be a double (floating point number)
Look to the function definition for information on what the function returns
All functions return only 1 (or zero) values. But the type of that one value is important.
double fahr2cels( double fahr );
Says that the function returns a value that is a double.
Take that information together, and make some changes to your code:
double dailyHighF, dailyHighC, dailyHighK;
double dailyLowF;
int lowHour;
dailyHighF = getDailyHigh();
dailyLowF = getDailyLow();
lowHour = getLowHour();
dailyHighC = farh2cels(dailyHighF);
dailyHighK = cels2kelv(dailyHighC);
Another thing to note: your functions are declared to return double, but they declare, scanf, and return ints. Its not a huge problem as the integers will get automatically changed into doubles. But you will be much better off if you are consistent in your types. If the function will return a double, it should have a double variable inside it.
e.g.
double fahr2cels( double fahr );
...
double fahr = 101.0;
double celsius = fahr2cels( fahr );
the return statment in the function returns the value to the caller.