השערת גולדבך מבואלתכנותמדעיוסטטיסטי R דוגמאות תכנות חלק 4.5 האם ניתן להציג כל מספר זוגי גדול מ- 2 כסכום של שני מספרים ראשוניים? תזכורת: 1 הוא לאמספר ראשוני, ו- 2 כן 4 = 2 + 2 10 = 3 + 7 = 5 + 5 6 = 3 + 3 12 = 5 + 7 8 = 3 + 5 14 = 3 + 11 = 7 + 7 זוהי בעיה פתוחה: חרף למעלה מ- 250 שנה של מאמצים מתמטיים, טרם נמצאה הוכחה שהתשובה היא "כן", או דוגמא נגדית (נבדקו כל הזוגיים עד 10) 18 מתמטיקאים משערים שהתשובה היא "כן" מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 2 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 1 השערת גולדבך השערת גולדבך נכתוב פונקציה המקבלת כארגומנט מספר זוגי, ומחזירה את מספרהדרכים בהן ניתן להציגו כסכום של שני ראשוניים (זהו "מספר גולדבך" של המספר הזוגי) הפונקציה בפעולה: > goldbach.no(10) [1] 2 > goldbach.no(100) [1] 6 > goldbach.no(1000) [1] 28 > goldbach.no(10000) [1] 127 נשתמש בפונקציית עזר המקבלת מספר טבעי, ומחזירה TRUE אם הוא ראשוני, ו- FALSE אחרת is.prime <- function(n){ if(n == 2) return(t) for(i in 2:sqrt(n)) if(n%%i == 0) return(f) return(t) יש דרכים יותר מהירות (אבל יותר מסובכות) לגלות האם מספר הוא ראשוני מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 4 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 3
המרת ספרות רומיות השערת גולדבך goldbach.no <- function(n){ count <- 0 i <- 2 while(i <= n/2){ if(is.prime(i) && is.prime(n - i)) count <- count + 1 i <- i + 1 return(count) הפונקציה הראשית: הרומאים כתבו מספרים באמצעות אותיות לטיניות: I = 1 VI = 6 X = 10 LX = 60 C = 100 II = 2 VII = 7 XX = 20 LXX = 70 CC = 200 III = 3 VIII = 8 XXX = 30 LXXX = 80 CCC = 300 IV = 4 IX = 9 XL = 40 XC = 90... V = 5 L = 50 למשל, XIV = 14, LXXXVII = 87, XCII = 92, CCXLIX = 249 נכתוב פונקציה שממירה מספר בספרות רומיות למספר עשרוני "רגיל": > roman.to.decimal("ccxlix") [1] 249 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 6 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 5 המרת ספרות רומיות הרעיון: נעבור על התווים במחרוזת הקלט זה אחר זה, ונבדוק כמה כל אחד מהם "תורם" למספר I תורם 1, אלא אם כן מימינו יש V או X, ואז הוא תורם 1 V תמיד תורם 5 X תורם 10, אלא אם כן מימינו יש L או C, ואז הוא תורם 10 L תמיד תורם 50 C תמיד תורם 100 (אצלנו) בעצם יש גם = 500 D ו- = 1000 M, אבל נניח שאותיות אלה לא מופיעות במחרוזת הקלט המרת ספרות רומיות roman.to.decimal <- function(s){ num <- 0 for(j in 1:nchar(s)){ if(substr(s,j,j) == "I") { if((substr(s,j+1,j+1)!= "V") && (substr(s,j+1,j+1)!= "X")) num <- num + 1 else num <- num - 1 if(substr(s,j,j) == "V") num <- num + 5 (המשך בעמוד הבא) מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 8 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 7
המרת ספרות רומיות if(substr(s,j,j) == "X") { if((substr(s,j+1,j+1)!= "L") && (substr(s,j+1,j+1)!= "C")) num <- num + 10 else num <- num - 10 if(substr(s,j,j) == "L") num <- num + 50 if(substr(s,j,j) == "C") num <- num + 100 return(num) "" sort) (bubble הוא שיטה ("אלגוריתם") למיון וקטור של מספרים זו שיטה פשוטה, אבל איטית עבור ווקטורים ארוכים הרעיון: משווים שוב ושוב איברים סמוכים בווקטור, ומחליפים ביניהם אם צריך דוגמא: נמיין את הווקטור (3 4), 8 1 בשלושה מעברים מעבר ראשון: מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 10 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 9 (4 8 1 3) (4 8 1 3) (4 8 1 3) (4 1 8 3) (4 1 8 3) (4 1 3 8) (4 1 3 8) (1 4 3 8) (1 4 3 8) (1 3 4 8) (1 3 4 8) (1 3 4 8) (1 3 4 8) (1 3 4 8) (1 3 4 8) (1 3 4 8) (1 3 4 8) (1 3 4 8) מעבר שני: מעבר שלישי: אם הווקטור הוא באורך n, צריך במקרה הגרוע ביותר (כשהמספר המינימלי נמצא בסוף) 1 n מעברים bubble.sort <- function(v){ n <- length(v) for(i in 1:(n-1)){ for(k in 1:(n-1)){ if(v[k] > v[k+1]){ temp <- v[k] v[k] <- v[k+1] v[k+1] <- temp return(v) מימוש ב- R : מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 12 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 11
ייעול: אחרי המעבר הראשון, המספר המקסימלי בטוח במקומו; אחרי השני, השני בגודלו בטוח במקומו, וכו' bubble.sort <- function(v){ n <- length(v) for(i in 1:(n-1)){ for(k in 1:(n-i)){ if(v[k] > v[k+1]){ temp <- v[k] v[k] <- v[k+1] v[k+1] <- temp return(v) ייעול נוסף: אם באחד המעברים לא התגלה צורך להחליף אף זוג איברים, הווקטור כבר ממוין, ואפשר לעצור נשתמש ב"דגל" (flag) משתנה לוגי, המציין האם הייתה החלפה במעבר האחרון מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 14 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 13 מגדלי האנוי bubble.sort <- function(v){ n <- length(v) for(i in 1:(n-1)){ swap.flag <- F for(k in 1:(n-i)){ if(v[k] > v[k+1]){ temp <- v[k] v[k] <- v[k+1] v[k+1] <- temp swap.flag <- T if(swap.flag == F) return(v) return(v).1.2 נתונים שלושה מוטות; על השמאלי מושחלות n דיסקיות, מסודרות מהגדולה (למטה) לקטנה (למעלה) המטרה: להעביר את כל הדיסקיות למוט הימני, כאשר מותר להזיז רק דיסקית אחת בכל שלב אסור להניח דיסקית על דיסקית קטנה ממנה מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 16 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 15
מגדלי האנוי מגדלי האנוי אנימציה למקרה = 4 n (באדיבות ויקיפדיה) כמה צעדים דרושים כדי לעמוד במשימה? הפתרון חייב לעבור דרך השלבים הבאים: מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 18 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 17 מגדלי האנוי מגדלי האנוי נסמן ב-( T(n את מספר הצעדים המינימלי הדרוש כדי לעמוד במשימה נוסחא רקורסיבית עבור :T(n) T(n) = 2T(n 1) + 1, T(1) = 1 פונקציה מתאימה ב- R : hanoi.towers <- function(n){ if(n > 1) return(2*hanoi.towers(n-1) + 1) else return(1) > hanoi.towers(2) [1] 3 > hanoi.towers(10) [1] 1023 > hanoi.towers(100) [1] 1.267651e+30 > hanoi.towers(1000) הפונקציה בפעולה: Error: evaluation nested too deeply: infinite recursion / options(expressions=)? כש"מתירים את הרקורסיה" (לא נלמד איך עושים זאת), מקבלים כי 1 n T(n) = 2 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 20 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 19
יש משוואות שקשה לפתור בשיטות ה"רגילות" למשל, מהו הפתרון של המשוואה הבאה? x 3 cos(x) = 0 נסמן: cos(x) f(x) = x 3 f היא רציפה, וכן f(0) = 1, f(1) = 0.459697 לכן חייב להיות ל- f שורש (מספר שכשמציבים אותו ב- f מקבלים 0) בין 0 ל- 1 לא נמצא את השורש במדויק, אבל נראה איך אפשר באמצעות R למצוא לו קירוב מצוין (למשל, בדיוק של 8 ספרות אחרי הנקודה העשרונית) צריך לדעת את ' f, הנגזרת של f f '(x) = 3x 2 + sin(x) הרעיון: להתחיל ממספר x 1 "באיזור" של השורש, להמשיך לקירוב טוב יותר x, 2 משם לקירוב עוד יותר טוב,x 3 וכו' מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 22 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 21 המשיק ל- f ב- x 1 חותך את ציר ה- x בנקודה x, 2 שהיא קרובה יותר לשורש שאנחנו מחפשים את הנקודה הבאה נמצא באותה השיטה ממשיכים הלאה לפי הנוסחה x 2 x 1 מתמטית, מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 24 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 23
מתי עוצרים? גישה מקובלת היא לעצור כאשר לראשונה מתקבל, x n+1 x n < ε עבור ε שהוא מספר קטן מאד (למשל, 8 10 = (ε השיטה בדרך כלל עובדת מצוין, ומתכנסת לשורש המבוקש תוך לא יותר מכמה עשרות צעדים לפעמים השיטה מתכנסת לשורש "לא נכון", או לא מתכנסת בכלל נכתוב פונקציה ב- R שמקבלת כארגומנט את x 1 (המספר ההתחלתי), ומחזירה פתרון למשוואה בדיוק של 8 ספרות אחרי הנקודה, תוך שהיא מדפיסה את סדרת הקירובים הפונקציה בפעולה: > newton(1) 1 0.8803329 0.8656842 0.865474 0.865474 [1] 0.865474 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 26 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 25 newton <- function(x.old){ repeat{ cat(x.old, "\n") fx <- x.old^3 - cos(x.old) dfx <- 3*x.old^2 + sin(x.old) x.new <- x.old - fx/dfx if(abs(x.old - x.new) < 10^(-8)) return(x.new) x.old <- x.new הפונקציה עצמה נשפר את הפונקציה כדי למנוע מהחיפוש להתבדר, נגביל את מספר האיטרציות נאפשר לקבוע בקריאה לפונקציה גם את מספר האיטרציות המקסימלי, וגם את תנאי ההתכנסות (כלומר את ε) מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 28 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 27
הפונקציה המשופרת: newton <- function(x.old, eps=10^(-8), iter.max=50){ i <- 0 repeat{ cat(x.old, "\n") fx <- x.old^3 - cos(x.old) dfx <- 3*x.old^2 + sin(x.old) x.new <- x.old - fx/dfx if(abs(x.old - x.new) < eps) return(x.new) if(i > iter.max) stop("too many iterations") x.old <- x.new i <- i + 1 אילו היינו רוצים למצוא שורש למשוואה אחרת, היינו צריכים לכתוב פונקציה חדשה הפתרון: f ו- 'f יועברו כארגומנטים לפונקציה newton לשם כך נשתמש בפונקציות substitute ו- eval הפונקציה בפעולה: > newton(x^3 - cos(x), 3*x^2 + sin(x), 1) 1 0.8803329 0.8656842 0.865474 0.865474 [1] 0.865474 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 30 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 29 הפונקציה עצמה newton <- function(f, df, x, eps=10^(-8), iter.max=50){ i <- 0 repeat{ cat(x,"\n") x.new <- x - eval(substitute(f))/eval(substitute(df)) if(abs(x - x.new) < eps) return(x.new) if(i > iter.max) stop("too many iterations") x <- x.new i <- i + 1 נשתמש בפונקציה כדי למצוא את השורש השלישי של 10 השורש הנ"ל הוא הפתרון של המשוואה f(x) = x 3 10 = 0 הנגזרת היא f '(x) = 3x 2 > newton(x^3-10, 3*x^2, 2) 2 2.166667 2.154504 2.154435 [1] 2.154435 הפתרון: מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 32 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 31
מציאת היום בשבוע מציאת היום בשבוע איזה יום בשבוע יהיה ה- 3 בנובמבר 2071? התשובה: יום שלישי נכתוב פונקציה המקבלת כארגומנטים יום, חודש ושנה, ומחזירה את היום בשבוע המתאים לתאריך הפונקציה בפעולה: > day.in.week(3, 11, 2071) [1] "Tuesday" כדי להימנע מסיבוכים, נצטמצם לתאריכים במאה ה- 21, כלומר בין 1.1.2000 ל- 31.12.2099 1.1.2000 היה יום שבת מספר הימים בחודשי השנה: ספטמבר - 30 אוקטובר - 31 נובמבר - 30 דצמבר - 31 מאי - 31 יוני - 30 יולי - 31 אוגוסט - 31 ינואר - 31 פברואר - 28/29 מרץ - 31 אפריל - 30 בפברואר יש 28 יום, אלא אם כן השנה מעוברת (כלומר מתחלקת ב- 4 ), ואז יש 29 החוקיות של שנים מעוברות היא בעצם יותר מורכבת, אבל התיאור לעיל נכון עבור המאה ה- 21 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 34 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 33 מציאת היום בשבוע נגדיר משתנה בשם,days שהוא מספר הימים בין 1.1.2000 לתאריך המבוקש היום בשבוע ייקבע לפי שארית החלוקה של days ב- 7 : אם השארית היא 0, זהו יום שבת אם השארית היא 1, זהו יום ראשון אם השארית היא 2, זהו יום שני... אם השארית היא 6, זהו יום שישי הפונקציה: מציאת היום בשבוע day.in.week <- function(d, m, y){ m.length <- c(0,31,28,31,30,31,30,31,31,30,31,30,31) days <- 365*(y - 2000) + sum(m.length[1:m]) + d + (y - 2000)%/%4 if((y%%4 == 0) && (m <= 2)) days <- days - 1 day.names <- c("saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday") return(day.names[(days%%7) + 1]) מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 36 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 35
במשחק נפוץ, צריך לאתר מילים בטבלה של אותיות: M C L A L Y R A B B I T S T O D O G F E L B N E נכתוב תכנית R שתפתור משחקים שכאלה נניח שהמילים כתובות רק משמאל לימין ומלמעלה למטה המילים וטבלת האותיות שמורות בשני קבצים נפרדים: letters.txt: MCLALY words.txt: LION RABBIT BAT STODOG DOG FELBNE RABBIT > solve.puzzle("letters.txt", "words.txt") LION 1 5 down BAT not found DOG 3 4 right RABBIT 2 1 right התכנית בפעולה: מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 38 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 37 הפונקציה הראשית: solve.puzzle <- function(letter.file, word.file){ letter.mat <- read.letter.table(letter.file) words <- read.words(word.file) for(w in words){ x <- search.word(w, letter.mat) if(x[1] == 0) cat(w, "not found\n") else{ direction <- ifelse(x[3] == 1, "right", "down") cat(w, x[1], x[2], direction, "\n") פונקציות עזר read.letter.table <- function(filename){ rows.vec <- scan(filename, "", sep="\n", quiet=t) m <- length(rows.vec) return(matrix(unlist(strsplit(rows.vec,"")), byrow=t, nrow=m)) read.words <- function(filename){ return(scan(filename, "", sep="\n", quiet=t)) מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 40 מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 39
search.word <- function(w, letter.mat){ m <- nrow(letter.mat) n <- ncol(letter.mat) k <- nchar(w) # searching from left to right for(i in 1:m){ for(j in 1:(n-k+1)){ s <- paste(letter.mat[i, j:(j+k-1)], collapse="") if(w == s) return(c(i,j,1)) # searching from top to bottom for(i in 1:(m-k+1)){ for(j in 1:n){ s <- paste(letter.mat[i:(i+k-1), j], collapse="") if(w == s) return(c(i,j,2)) return(0) מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 42 (המשך בעמוד הבא) מבוא לתכנות מדעי וסטטיסטי R חלק 4.5 סמסטר ב' תש"ף, 2019/20 41