מבוא לתכנות ולמדעי המחשב בשפת C/מתמטיקה, הערות ומשפט תנאי.: הבדלים בין גרסאות בדף

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי
Hidro (שיחה | תרומות)
אין תקציר עריכה
Matanya (שיחה | תרומות)
מ 4 גרסאות
(אין הבדלים)

גרסה מ־18:06, 31 באוקטובר 2012

תבנית:ניווט מבוא


שימוש בכלים מתמטיים

עד כה ראינו שימוש באריטמתיקה בסיסית - ארבעת פעולות החשבון. בכדי להשתמש בכלים מתמטיים נוספים, יש להוסיף שורה אחת שגורמת להכללת הספריה המתמטית של C. לדוגמה:


#include <stdio.h>
#include <math.h> 
 
int main() {
  
	printf("sqrt(144) = %f, fabs(-14) = %f, sin(M_PI/2) = %f, pow(2,8) = %f \n", sqrt(144), fabs(-14), sin(M_PI/2), pow(2,8) ); 
	return 0; 
}

פלט:

sqrt(144) = 12.000000, fabs(-14) = 14.000000, sin(M_PI/2) = 1.000000, pow(2,8) = 256.000000

הסבר: השורה השניה בקוד היא זו שאחראית להכללת הספריה המתמטית, האלמנט שמאפשר שימוש בשאר הכלים המתמטיים שבהמשך הקוד. החישובים לפי סדר הדפסתם הם: השורש הריבועי (square root) של 144, הערך המוחלט (absolute value) של 14-, הסנוס של חצי פיי רדיאנים והערך של 8^2.

בכדי לאפשר את שילוב הספריה המתמטית יש להוסיף גם את הפרמטר lm- לפקודת הקומפילציה:

gcc -lm check.c -o check

לא נכנס כרגע לסיבה שבגללה יש צורך בתוספת הזאת.

הספריה המתמטית מספקת עוד הרבה כלים, ניתן לראות פירוט שלהם כאן.

קוד מסכם לידע עד כה

הגענו לשלב בו אנחנו יכולים לכתוב קוד שעושה משהו שימושי. התוכנית שנכתוב תקבל מהמשתמש שלושה מספרים שייצגו את הפרמטרים במשוואה ריבועית ותדפיס על המסך את הפתרונות שלה. החישוב יתבצע ע"י שימוש בנוסחה המוכרת לשורשי משוואה ריבועית:

<m>

x_{1,2} = \frac{-b \pm \sqrt{b^2-4 a c}}{2a}

</m>

(אפשר לקרוא עליה יותר בויקיפדיה)

הנה קוד אפשרי:


#include <stdio.h>
#include <math.h> 

int main() {

	printf("Please enter the three coefficients of a quadratic equation\n(a*x^2+b*x+c=0)\n"); 

	double a,b,c; 
 	printf ("a: "); 
	scanf("%lf",&a);

	printf ("b: "); 
	scanf("%lf",&b);

	printf ("c: "); 
	scanf("%lf",&c);

	double d = sqrt(b*b-4*a*c); 
	
	printf("x1 = %.2lf, x2 = %.2lf \n",(-b+d)/(2*a),(-b-d)/(2*a));    
	return 0; 
}

פלט:

Please enter the three coefficients of a quadratic equation
(a*x^2+b*x+c=0)
a: 3
b: 51
c: 210
x1 = -7.00, x2 = -10.00

הערות (comments)

בכל שפת תכנות (לפחות כל אלה ששמעתי אודותם) קיימת אפשרות לכתוב תוכן שהקומפיילר מתעלם ממנו התעלמות מוחלטת. האפשרות הזאת יכולה להראות מוזר בהתחלה אבל יש לה חשיבות רבה. חשוב לזכור שלא רק הקומפיילר קורא את הקוד שאנחנו כותבים. גם אנחנו וגם אנשים נוספים שירצו להבין מה עשינו, להוסיף, לשנות או לתחזק את הקוד.

לאנשים חשוב להבין את המשמעות של הדברים שכתובים. חשוב להם להבין מה המטרה, מה תפקיד כל חלק בקוד וכ'. לקומפיילר זה לא חשוב, הוא רק מתרגם את הקוד. גם למחשב המבצע זה לא חשוב, הוא מבצע בלי להבין משמעויות. לאדם הצורך הזה קריטי, אם הוא לא מבין מה קורה בקוד, מה הכוונה, הוא לא יכל לשנות אותו, רק להריץ אותו.

ב C יש שתי אפשרויות לכתוב הערות. האחת היא שימוש בסימון /*...*/. סימונים אלה פועלים כמו סוגריים שתוחמים קטע בקובץ ממנו הקומפיילר מתעלם. השניה היא שימוש בסימון // שמאפשר כתיבת הערה החל מהסימון הזה ועד לסיום השורה.

הנה דוגמה:

#include <stdio.h> 
/* This is a very interesting program. 
It manages to capture the delicate relationship between 
the computer and the user. 
*/ 
int main() {
	printf("hello lord\n"); // this is the key point 
	return 0; 
}

מבחינת התפקוד, תוכנית זו שקולה לתוכנית הראשונה שכתבנו (hello world) אבל היא כוללת הסברים שנועדו לבני אדם והקומפיילר מתעלם מהם.


שימוש נפוץ נוסף היערות נקרא comment out (ו - uncomment). לפעמים, במהלך הפיתוח אנו מעוניינים לנטרל חלקים מסויימים של הקוד ולראות איך התוכנות מתפקדת בלעדיהם. אנו לא מעוניינים למחוק אותם כי יכל להיות שנשתמש בהם בעתיד.

הנה דוגמה:

#include <stdio.h> 
/* This is a very interesting program. 
It manages to capture the delicate relationship between 
the computer and the user. 
*/ 
int main() {
/*
	printf("hello lord\n"); // this is the key point 
*/ 
	return 0; 
}

במצב זה התוכנית לא מבצעת דבר אבל אפשר בקלות להחזיר אותה למצב הקודם.

יש לשים לב שהערה בתוך הערה עלולה לבלבל את הקומפייר, כמו בדוגמה הבאה:

#include <stdio.h> 
/* This is a very interesting program. 
It manages to capture the delicate relationship between 
the computer and the user. 
*/ 
int main() {
/*
	/* bla bla */ printf("hello lord\n"); // this is the key point 
*/ 
	return 0; 
}

תוכנית זו לא תעבור קומפילציה מכיוון שכאשר הקומפיילר מוצא את סימן "סגור הערה" הוא סוגר את ההערה החיצונית ולא את הפנימית (אין לו מנגנון של סוגריים מאוזנים). אפשר לראות את הבעיה הזאת גם כאן באמצעות מנגנון הצביעה האוטומטי שבו משתמש הויקי הזה לצבוע את הקוד. שימו לב שסוגר ההערה האחרונה הוא בצבע ירוק ושהקוד לפניו איננו צבוע כהערה.

בגלל תופעות כאלה, כדאי לשים לב ולהשתמש בשני סוגי ההערות או להשתמש בסימון // בתחילת כל שורה למטרות comment out (יש עורכי טקסט שתומכים בפעולה).

פקודת תנאי - if

כאמור, תוכנית מחשב היא סדרת פקודות שאמורה להביא למטרה רצויה. בכדי שנוכל לכתוב תוכניות מעניינות יש צורך בנקודות התפצלות, נקודות שבהם נשאלת שאלה שמפרידה למקרים כך שבכל מקרה מתרחש משהו אחר. הפקודה שמאפשרת זאת בשפת C היא if (אם). הנה דוגמה פשוטה:

 

#include <stdio.h>

int main() {

	printf("Please enter your age: "); 
	int age; 
	scanf("%d",&age); 
	
	if(age < 13) 
		printf("Hey, you're just a kid!\n");  
	else
		printf("OK, you are an adult\n"); 	
		
	return 0; 
}

הרצה בה המשתמש הקליד 34:

Please enter your age: 34 
OK, you are an adult

הרצה בה המשתמש הקליד 12:

Please enter your age: 12 
Hey, you're just a kid!

תחביר

פקודת if יכולה להכתב בשתי דרכים. ללא else:

if (תנאי) 
    בלוק קוד

או עם else:

if (תנאי) 
    בלוק קוד	
else
    בלוק קוד

בלוק קוד יכל להיות פקודה בודדת או אוסף פקודות המוקפות בסוגריים מסולסלים.

קינון (nesting)

בכל בלוק קוד אפשר לכתוב כל קוד חוקי ב C. בפרט, ניתן לכתוב פקודות תנאי נוספות. כתיבה כזו נקראת קינון (nesting). כמו קן בתוך קן.

התוכנית הבאה משתמשת בקינון בשביל להבין איזה מספר הוגרל בתחום בין 1 ל 4. לאחר שמצאה את המספר, היא מדפיסה אותו באנגלית.

 
#include <stdio.h>

#include <stdlib.h> // required for random() and srand  
#include <time.h>   // required for time()  

int main() {

	srand(time(0));       // initialize the random generator using the time 
	int n = rand()%4 + 1; // generate a random integer in the range 1..4 
	
	printf("In English, %d is ",n); 
	if(n<=2) {
		if(n==1)
			printf("One"); 
		else 
			printf("Two");  
	}
	else {
		if(n==3)
			printf("Three");
		else
			printf("Four"); 
	}
	printf("\n"); 
	return 0; 
}

(בשלב זה אין חשיבות להבין את הפקודות המתועדות. כל תפקידם הוא לדאוג להגרלת מספר שלא חוזרת על עצמה)

פלט לדוגמה:

In English, 4 is Four

הרצה נוספת עשויה לתת:

In English, 3 is Three

פרדיקטים

פרדיקטים הם הביטויים שיכולים להופיע בתור תנאים. הערך שלהם חייב להיות אמת או שקר. לדוגמה, הביטוי i<10 הוא פרדיקט. אם ערכו של i קטן מ 10 אז ערך הפרדיקט הוא "אמת" אחרת הוא "שקר". ניתן דוגמה למספר פרדיקטים נוספים בכדי להכיר את התחביר:

  • i==10 - ערך הפרדיקט "אמת" אם"ם הערך של i שווה ל 10. שימו לב להבדל בין פרדיקט זה לבין ביטוי ההשמה i=10.
  • i!=10 - ערך הפרדיקט "אמת" אם"ם הערך של i שונה מ 10.
  • i >= 10 - ערך הפרדיקט "אמת" אם i גדול או שווה ל 10. באופן דומה:i<=10 - קטן או שווה.

פרדיקטים הבנויים מפרדיקטים אחרים

  • הפרדיקט i>10 && i <20 מקבל את הערך "אמת" אם"ם i>10 וגם i<20. הסימון && מסמל ב C את השער הלוגי "וגם" (AND).
  • i<10 || i>20 - אמיתי כאשר i קטן מ 10 או גדול מ 20. || מסמל ב C את השער הלוגי "או" (OR)

אפשר כמובן לשלב את כולם באופנים שונים. לדוגמה:

if( (i > 10 && i <= 20) || (i >= 100 && i != 102)) {..}

שימוש בפקודת תנאי בשביל לשפר קוד קודם

נתבונן שוב בקוד שכתבנו למציאת שורשים של משוואה ריבועית:

#include <stdio.h>
#include <math.h> 

int main() {

	printf("Please enter the three coefficients of a quadratic equation\n(a*x^2+b*x+c=0)\n"); 

	double a,b,c; 
 	printf ("a: "); 
	scanf("%lf",&a);

	printf ("b: "); 
	scanf("%lf",&b);

	printf ("c: "); 
	scanf("%lf",&c);

	double d = sqrt(b*b-4*a*c); 
	
	printf("x1 = %.2lf, x2 = %.2lf \n",(-b+d)/(2*a),(-b-d)/(2*a));    
	return 0; 
}

האם הקוד הזה עובד נכון עבור כל פלט אפשרי? האם התוכנית שלנו מכילה באגים?

מה יקרה אם נכניס את הערכים הבאים: a=1, b=0, c=1? קלט זה מייצג את המשוואה: <m> x^2 + 1 = 0 </m>

משוואה ללא פתרונות ממשיים. אם ננסה להריץ את התוכנית שלנו על קלט כזה, נקבל את הפלט הבא:

Please enter the three coefficients of a quadratic equation
(a*x^2+b*x+c=0)
a: 1
b: 0
c: 1
x1 = -nan, x2 = -nan

nan (או nan-) הוא הערך שמקבלים ב C מנסיון לחשב שורש של מספר שלילי (קיצור של not a number). במקרה שלנו, תוצאה של נסיון חישוב שורש ריבועי של 3 שאיננו מספר ממשי.

נשנה את הקוד שלנו לבדוק את ערך הדסקמיננטיה ולפעול בהתאם. אם היא שווה ל 0, יש רק פתרון אחד ואם היא שלילית, אין פתרונות ממשיים:

#include <stdio.h>
#include <math.h> 
 
int main() {
 
	printf("Please enter the three coefficients of a quadratic equation\n(a*x^2+b*x+c=0)\n"); 
 
	double a,b,c; 
 	printf ("a: "); 
	scanf("%lf",&a);
 
	printf ("b: "); 
	scanf("%lf",&b);
 
	printf ("c: "); 
	scanf("%lf",&c);
 
	double d = b*b-4*a*c;
	
	if (d < 0)
		printf ("There are no real solutions to this equation\n");
	else 
		if (d==0)  
			printf("x = %.2lf \n",-b/(2*a));
		else {		   
			d = sqrt(d);
			printf("x1 = %.2lf, x2 = %.2lf \n",(-b+d)/(2*a),(-b-d)/(2*a));    
		}

	return 0; 
}

פלט:

Please enter the three coefficients of a quadratic equation
(a*x^2+b*x+c=0)
a: 1
b: 0
c: 1
There are no real solutions to this equation
Please enter the three coefficients of a quadratic equation
(a*x^2+b*x+c=0)
a: 1
b: 0
c: -1
x1 = 1.00, x2 = -1.00


האם כעת הקוד נקי מבאגים? נסו לחשוב מה קורה כאשר המשתמש מכניס ל a את הערך 0.


תבנית:ניווט מבוא