Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C)...
Transcript of Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C)...
Εισαγωγή στο TDDTest Driven
Development
Δομημένος ΠρογραμματισμόςΤσαγκατάκης Ιωάννης
2
Πως λύνουμε ένα πρόβλημα ;
ΣχεδιασμόςΑλγορίθμου
Κώδικας (υλοποίηση)
Profit !
3
Άσκηση 4Γράψτε ένα πρόγραμμα το οποίο θα βρίσκει και θα εμφανίζει στη οθόνη όλους τους τετραψήφιους αριθμούς που είναι ίσοι με το άθροισμα των ψηφίων τους στη τέταρτη δύναμη.
Α Β C D
0...9
1...9
Ένα κόμμα κάνει την διαφορά
#include <math.h>
int a, b, c, d, x;
int sum1 = pow(a, 4) + pow(b, 4) + pow(c, 4) + pow(d, 4);
int sum2 = pow(a + b + c + d, 4);
4
undefined reference to `pow'● Χρειάζεται την βιβλιοθήκη libm
gcc -Wall -Wconversion -o ex4 -lm ex4.c
● cmake cmake_minimum_required(VERSION 3.15 )project(Ergasia1 C)add_compile_options(-Wall -Wextra -Wconversion -Wpedantic)
add_executable(ex1 ex1.c)add_executable(ex4 ex4.c)target_link_libraries(ex4 m)
5
undefined reference to `pow'● Περιφραστικά
● Συνάρτηση
int sum3= a*a*a*a + b*b*b*b + c*c*c*c + d*d*d*d;
int pow4(int num) { int result = num * num * num * num; return result;}
6
Μια απλή λύσηint main() { for (int a = 1; a <= 9; a++) { for (int b = 0; b <= 9; b++) { for (int c = 0; c <= 9; c++) { for (int d = 0; d <= 9; d++) {
// Horner method int x = (((a * 10) + b) * 10 + c) * 10 + d;
int sum = pow(a, 4) + pow(b, 4) + pow(c, 4) + pow(d, 4); if (sum == x) { printf("Solution found %d\n", x); } } } } }}
Solution found 1634Solution found 8208Solution found 9474
Είναι σωστά;
7
Μια (αυστηρή) κριτική της λύσης● Δουλεύει μόνο για 4ψήφιους αριθμούς
– Αν αύριο μας ζητήσουν για 5-ψήφιους αριθμούς;● Κάνει πολλά πράγματα μπλεγμένα μεταξύ τους
– Παραγωγή 4-ψήφιων αριθμών – Έλεγχος της συνθήκης φιλτραρίσματος. Αν αύριο αλλάξει;
● Πάντα αναζητούμε ποιο γενικές λύσεις● Αυτά δεν είναι προβλήματα στο επίπεδο που είμαστε,
αλλά καλό να το έχουμε υπόψιν μας
8
Μια συνήθης λύση#include <math.h>#include <stdbool.h>#include <stdio.h>
int main() { bool isFound = false; int a, b, c, d; for (int x = 1000; x <= 9999; x++) { a = 0; b = 0; c = 0; d = 0; int sum = pow(a, 4) + pow(b, 4) + pow(c, 4) + pow(d, 4); if (sum == x) { printf("Solution found %d\n", x); isFound = true; } }
if (isFound == false) { puts("No solutions found"); }}
9
Ο λογικός τύπος bool // Old Ctypedef int bool;#define true 1#define false 0
// C99#include <stdbool.h>
10
Μια συνήθης λύση (μικρά προβλήματα)
#include <math.h>#include <stdbool.h>#include <stdio.h>
int main() { bool isFound = false; int a, b, c, d; for (int x = 1000; x <= 9999; x++) { a = 0; b = 0; c = 0; d = 0; double sum = pow(a, 4) + pow(b, 4) + pow(c, 4) + pow(d, 4); if (sum == x) { printf("Solution found %d\n", x); isFound = true; } }
if (isFound == false) { puts("No solutions found"); }}
warning: conversion to ‘int’ from ‘double’ mayalter its value [-Wfloat-conversion]
Αυτά θέλουν σκέψη,ας το καθυστερήσουμε λιγάκι
Έτσι θα ξέρω και πως αυτό θα δουλέψει !
11
Test Driven Development● Σπάω το πρόβλημα
σε μικρότερα και απλούστερα
● Βεβαιώνομε πως κάθε τι είναι σωστό
● Ο αλγόριθμος θα προκύψει
12
Τα assertions● Το TDD του φτωχού● Μια συνθήκη που αν δεν είναι αληθής
– Σε Release mode δεν υπάρχουν● δεν θα κάνουν τίποτα, ούτε θα παραχθεί κώδικας
– Σε Debug mode● Θα σταματήσουν βίαια την εκτέλεση του προγράμματος● Με ένα Debugger θα δούμε την λάθος τιμή.
13
Εισαγωγή στα assertions#include <assert.h>
int main() { int x = 4712; int a, b, c, d; a = 0; b = 0; c = 0; d = 0;
assert(a == 4); assert(b == 7); assert(c == 1); assert(d == 2);
puts("All assertions passed !");}
main: Assertion `a == 4' failed.
Ας το φτιάξουμε
14
Εισαγωγή στα assertions#include <assert.h>
int main() { int x = 4712; int a, b, c, d; a = 4; b = 7; c = 1; d = 2;
assert(a == 4); assert(b == 7); assert(c == 1); assert(d == 2);
puts("All assertions passed !");}
Ας το φτιάξουμεστα αλήθεια
15
Βήμα 2: Assertion pass● Ο κώδικας δουλεύει● Υπάρχει κάποια κρυμμένη δομή; ● Μπορεί να γίνει ποιο γενικός;
int x = 4712;
int d = x % 10;int a = x / 1000;
int b = (x / 100) % 10;int c = (x / 10) % 10;
assert(a == 4);assert(b == 7);assert(c == 1);assert(d == 2); int a = x / 1000; // 3
int b = (x / 100) % 10; // 2 int c = (x / 10) % 10; // 1int d = x % 10; // 0
16
Αναζητώντας ένα γενικό τύπο● Ο κώδικας δουλεύει● Υπάρχει κάποια κρυμμένη δομή; ● Μπορεί να γίνει ποιο γενικός;
int a = x / 1000; // 3int b = (x / 100) % 10; // 2 int c = (x / 10) % 10; // 1int d = x % 10; // 0
// 1st passint a = (x / 1000) % 10; // 3int b = (x / 100) % 10; // 2 int c = (x / 10) % 10; // 1int d = (x / 1) % 10; // 0
// 2nd passint a = (x / 10^3) % 10; // 3int b = (x / 10^2) % 10; // 2 int c = (x / 10^1) % 10; // 1int d = (x / 10^0) % 10; // 0
17
Βήμα 3 : Refactoringint ipow(int num, int to) { double result = pow(num, to); return (int)result;}
int main() { int x = 4712;
int a = (x / ipow(10, 3)) % 10; // 3 int b = (x / ipow(10, 2)) % 10; // 2 int c = (x / ipow(10, 1)) % 10; // 1 int d = (x / ipow(10, 0)) % 10; // 0
assert(a == 4); assert(b == 7); assert(c == 1); assert(d == 2);
int sum = ipow(a, 4) + ipow(b, 4) + ipow(c, 4) + ipow(d, 4); assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674
puts("All assertions passed !");}
18
Βήμα 3.1 : Refactoring with forint ipow(int num, int to) { double result = pow(num, to); return (int)result;}
int main() { int x = 4712; int digits = 4;
int sum = 0; for(int i=0; i< digits; i++) { int digit = (x / ipow(10, i)) % 10; sum = sum + ipow(digit,4); }
assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674 puts("All assertions passed !");}
19
Βήμα 3.2 : Refactoring no doublesint ipow(int num, int to) { int result = 1; for (int i = 0; i < to; i++) result *= num; return result;}
int main() { int x = 4712; int digits = 4;
int sum = 0; for(int i=0; i< digits; i++) { int digit = (x / ipow(10, i)) % 10; sum += ipow(digit,4); }
assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674 puts("All assertions passed !");}
20
Βήμα 3.3int ipow(int num, int to) { int result = 1; for (int i = 0; i < to; i++) result *= num; return result;}
int main() { int x = 4712; int digits = 4;
int sum = 0; for(int i=0; i< digits; i++) { int digit = (x / ipow(10, i)) % 10; sum += ipow(digit,4); }
assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674 puts("All assertions passed !");}
Χωρίςαυτό;
21
Βήμα 3.3 : Refactoring do..whileint main() { int x = 4712;
...
int sum2 = 0; int num = x; do { int digit = num % 10; sum2 = sum2 + ipow(digit, 4); num = num / 10; } while ( num != 0 );
assert(sum2==sum);
...}
ΟΚ
22
Βήμα 3.4 int main() { int x = 4712;
...
int sum2 = 0; int num = x; do { int digit = num % 10; sum2 = sum2 + ipow(digit, 4); num = num / 10; } while ( num != 0 );
assert(sum2==sum);
...}
Συνάρτηση;
23
Βήμα 3.4 : Refactoring to functionsint ipow(int num, int to);int calculateSquare4(int num);
int calculateSquare4(int num) { int sum = 0; do { int digit = num % 10; sum += ipow(digit, 4); num = num / 10; } while ( num != 0 ); return sum;}
int main() { int x = 4712; int sum = calculateSquare4(x);
assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674 puts("All assertions passed !");}
24
Βήμα 3.5 : Βελτιστοποιώντας την ipow
● Εφόσον τα πάντα είναι στην θέση τους μπορώ να κάνω με ασφάλεια μικρές πινελιές απόδοσης
int ipow4(int num);
int ipow4(int num) { int temp = num * num; return temp *temp;}
25
Το τελικό πρόγραμμαint main() { bool isFound = false;
for (int x = 1000; x <= 9999; x++) { int sum = calculateSquare4(x); if (sum == x) { printf("A solution found %d\n", x); isFound = true; } }
if (isFound == false) { puts("No solutions found"); }}
26
Συμπεράσματα● Καταλήξαμε (σχεδόν αυτόματα!) σε ένα κομψό αλγόριθμο● Εύκολα κατανοητός και με ευκολία αλλαγής
– Τα assertions μας προστάτευαν από τα λάθη μας– Πόσο εύκολα αλλάζει αν κάναμε λάθος στο “,” της εκφώνησης;
● Ποιο γενικός κώδικας– Δουλεύει με αριθμούς οποιουδήποτε μεγέθους.– Δεν χρησιμοποιεί αριθμούς κινητής υποδιαστολής
27
Μικροβελτιστοποιήσεις● Μια μοντέρνα CPU είναι πολύπλοκη.● Δεν είναι όλες οι πράξεις ίδιες.● Δεν είναι όλες οι προσβάσεις στην μνήμη ίδιες● Η κλίμακα είναι λογαριθμική● Η πρόσβαση στην μνήμη συχνά ποιο σημαντική
από τον αλγόριθμο● Μια απλή αλλαγή μπορεί να αλλάξει την ταχύτητα
Χ100 φορές.● Μόνο με μετρήσεις μπορούμε να ξτο
τεκμηριώσουμε,● Δεν θα ασχοληθούμε με αυτό περαιτέρω
28
Ήταν δύσκολο;
“Πονάει πάντα η πρώτη φορά”Γιάννης Αγγελάκας, Τρύπες