7. Εκφράσεις και προτάσεις εκχώρησης
7.2 Αριθμητικές εκφράσεις
Παράδειγμα με μεγάλους αριθμούς στη Python
large_numbers.py |
---|
| import math
def factorial(n):
return math.factorial(n)
# Calculate factorial of 100
large_factorial = factorial(100)
print(f"The factorial of 100 is: {large_factorial}")
|
$ python large_numbers.py
The factorial of 100 is: 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Παράδειγμα με μεγάλους αριθμούς στη C
large_numbers.c |
---|
| #include <stdio.h>
#include <gmp.h>
void factorial(mpz_t result, unsigned long n) {
mpz_t temp;
mpz_init_set_ui(result, 1);
mpz_init_set_ui(temp, 1);
for (unsigned long i = 2; i <= n; i++) {
mpz_mul_ui(temp, temp, i);
mpz_set(result, temp);
}
mpz_clear(temp);
}
int main(void) {
mpz_t large_factorial;
mpz_init(large_factorial);
factorial(large_factorial, 100);
gmp_printf("The factorial of 100 is: %Zd\n", large_factorial);
mpz_clear(large_factorial);
return 0;
}
|
Εγκατάσταση της βιβλιοθήκης GMP σε Linux
$ sudo apt update
$ sudo apt install libgmp-dev
$ gcc -o factorial factorial.c -lgmp & ./a.out
The factorial of 100 is: 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
7.2.1 Σειρά αποτίμησης τελεστών
expressions.py |
---|
| print(3 / 2) # εκτυπώνει 1.5
print(3 // 2) # εκτυπώνει 1
print(-7 // 2) # εκτυπώνει -4 (στρογυλλοποίηση προς μικρότερο ακέραιο αριθμό)
print(2 + -3 * 4) # εκτυπώνει -10 (υψηλότερη προτεραιότητα του μοναδιαίου - από το *)
# fmt:off
print(2 * 3 * 4) # εκτυπώνει 24 (από αριστερά προς τα δεξιά αποτίμηση για τον τελεστή *, όπως και για +, -, /)
print(2**3**2) # εκτυπώνει 512 (από δεξιά προς τα αριστερά αποτίμηση για τον τελεστή **)
print(-2**4) # εκτυπώνει -16 (υψηλότερη προτεραιότητα του ** από το μοναδιαίο -)
# fmt: on
print(2 < 3 and 3 < 4) # εκτυπώνει True
print(2 < 3 < 4) # εκτυπώνει True (ισοδύναμο με το παραπάνω)
# fmt:off
print(3 & 5) # εκτυπώνει 1, διότι οι αριθμοί μετατρέπονται σε δυαδικούς και γίνεται η πράξη bitwise AND
# fmt: on
|
expressions.c |
---|
| #include <limits.h>
#include <stdio.h>
int main() {
printf("%d\n", 3 / 2); // 1 (ακέραια διαίρεση)
printf("%d\n",
-7 / 2); // -3 (στρογγυλοποίηση προς το μηδέν, όχι -4 όπως η Python)
printf("%d\n", 2 < 3 < 4); // εκτυπώνει 1, διότι (2 < 3) -> 1, (1 < 4) -> 1
printf("%d\n",
2 < (3 < 4)); // εκτυπώνει 0, διότι (3 < 4) -> 1, (2 < 1) -> 0
printf("%d\n",
INT_MAX + 1); // undefined behavior (μπορεί να είναι οτιδήποτε)
printf("%d\n", 'a' * 'b'); // 97 * 98 = 9506 (αναβάθμιση σε ακεραίους)
int i = 10;
printf("%d\n", i++ + i++); // undefined behavior (μπορεί να είναι οτιδήποτε)
}
|
7.2.1.6 Εκφράσεις υπό συνθήκη (conditional expressions)
conditional_expression.c |
---|
| #include <stdio.h>
int main() {
int x = 10, y = 20;
int max = (x > y) ? x : y;
printf("The maximum value is: %d\n", max);
int num = 15;
printf("%d is %s\n", num, (num % 2 == 0) ? "even" : "odd");
int a = -5;
printf("%d is %s\n", a, (a > 0) ? "positive" : (a < 0) ? "negative" : "zero");
return 0;
}
|
$ gcc conditional_expression.c && ./a.out
The maximum value is: 20
15 is odd
-5 is negative
7.2.2 Σειρά αποτίμησης τελεστέων
7.2.2.1 Παρενέργειες (side-effects)
side_effects.c |
---|
| #include <stdio.h>
int a = 5;
int fun1() {
a = 17;
return 3;
}
int main() {
a = a + fun1(); // udefined behavior
printf("Result: %d\n", a);
return 0;
}
|
7.2.2.2 Αναφορική διαφάνεια (referential transparency)
Παράδειγμα παραβίασης της αναφορικής διαφάνειας στη C
no_referential_transparency.c |
---|
| #include <stdio.h>
int counter = 0; // Global variable affecting function behavior
int nonReferentialTransparentFunction(int x) {
counter++; // Side effect: modifies global state
return x + counter;
}
int main() {
int a = 5;
// Calling the function multiple times with the same argument
printf("First call: %d\n", nonReferentialTransparentFunction(a));
printf("Second call: %d\n", nonReferentialTransparentFunction(a));
printf("Third call: %d\n", nonReferentialTransparentFunction(a));
return 0;
}
|
$ gcc no_referential_transparency.c && ./a.out
First call: 6
Second call: 7
Third call: 8
7.3 Υπερφορτωμένοι τελεστές
Παράδειγμα σε Python
operator_overload.py |
---|
| class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# Overload the + operator
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
# Overload the string representation
def __str__(self):
return f"({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2
print(p3)
|
$ python operator_overload.py
(4,6)
Παράδειγμα σε C++
operator_overload.cpp |
---|
| #include <iostream>
using namespace std;
class Point {
public:
int x, y;
Point(int x, int y) : x(x), y(y) {}
Point operator+(const Point& other) {
return Point(x + other.x, y + other.y);
}
friend ostream& operator<<(ostream& os, const Point& p) {
os << "(" << p.x << ", " << p.y << ")";
return os;
}
};
int main() {
Point p1(1, 2);
Point p2(3, 4);
Point p3 = p1 + p2;
cout << p3 << endl;
return 0;
}
|
$ g++ operator_overload.cpp && ./a.out
(4,6)
7.4 Μετατροπές τύπων
widening_narrowing.c |
---|
| #include <stdio.h>
int main() {
// Widening Conversions (ασφαλής)
int smallInt = 100;
float wideFloat = smallInt; // int -> float
double wideDouble = wideFloat; // float -> double
printf("Widening Conversions:\n");
printf("int to float: %d → %f\n", smallInt, wideFloat);
printf("float to double: %f → %lf\n\n", wideFloat, wideDouble);
// Narrowing Conversions (επικίνδυνο)
double largeDouble = 123456.789;
float narrowFloat =
largeDouble; // double -> float (πιθναή απώλεια ακρίβειας)
int narrowInt = narrowFloat; // float → int (αποκοπή δεκαδικών ψηφίων)
printf("Narrowing Conversions:\n");
printf("double to float: %lf → %f\n", largeDouble, narrowFloat);
printf("float to int: %f → %d\n\n", narrowFloat, narrowInt);
// Overflow in Narrowing
unsigned char narrowChar = 300; // char (0-255), 300 wraps around
printf("Overflow in Narrowing:\n");
printf("300 stored in unsigned char: %d\n",
narrowChar); // Output: 44 (300 % 256)
return 0;
}
|
$ gcc widening_narrowing.c && ./a.out
widening_narrowing.c:24:30: warning: implicit conversion from 'int' to 'unsigned char' changes value from 300 to 44 [-Wconstant-conversion]
24 | unsigned char narrowChar = 300; // char (0-255), 300 wraps around
| ~~~~~~~~~~ ^~~
1 warning generated.
Widening Conversions:
int to float: 100 → 100.000000
float to double: 100.000000 → 100.000000
Narrowing Conversions:
double to float: 123456.789000 → 123456.789062
float to int: 123456.789062 → 123456
Overflow in Narrowing:
300 stored in unsigned char: 44
7.5 Σχεσιακές και Boolean εκφράσεις
equality_vs_identity.py |
---|
| # Ανάθεση (=)
a = [1, 2, 3] # 'a' δείχνει σε ένα αντικείμενο λίστας
# Ισότητα (==)
b = [1, 2, 3]
print(a == b) # True -> και οι δύο λίστες έχουν το ίδιο περιεχόμενο
# ταυτότητα (is)
print(a is b) # False -> Διαφορετικά αντικείμενα στη μνήμη
# Ταυτότητα σε immutable τύπους
x = 5
y = 5
print(x == y) # True -> ϊδια τιμή
print(
x is y
) # True -> Οι μικροί ακέραιοι γίνονται cache, συνεπώς x, y αναφέρονται στο ίδιο αντικείμενο
# Ταυτότητα με mutable τύπους
c = a # η μεταβλητή c αναφέρεται στην ίδια λίστα με την μεταβλητή a
print(a is c) # True -> η c και η a είναι το ίδιο αντικείμενο στη μνήμη
# Οι αλλαγές στο a επηρεάζουν και το c
a.append(4)
print(c) # [1, 2, 3, 4]
# Χρήση του is σε strings
s1 = "hello"
s2 = "hello"
print(s1 == s2) # True -> Ίδια περιεχόμενα
print(
s1 is s2
) # True -> Τα μικρά strings γίνονται cache, συνεπώς s1, s2 αναφέρονται στο ίδιο αντικείμενο
# Αλλά με μεγαλύτερα αντικείμενα (πο μπορεί να μη γίνουν interned)
s3 = "hello world, this is a long string" * 1000
s4 = "hello world, this is a long string" * 1000
print(s3 == s4) # True -> ίδιο περιεχόμενο
print(s3 is s4) # Μπορεί να είναι False -> Διαφορετικά αντικείμενα στη μνήμη
|
7.6 Εσπευσμένη αποτίμηση εκφράσεων
short_circuit.c |
---|
| #include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int size = sizeof(arr) / sizeof(arr[0]);
int i = 0;
// Αναζήτηση ενός στοιχείου με short-circuit σε επανάληψη
while (i < size && arr[i] != 30) {
i++;
}
if (i < size) {
printf("Found 30 at index %d\n", i);
} else {
printf("30 not found\n");
}
return 0;
}
|
$ gcc short_circuit.c && ./a.out
Found 30 at index 2
7.7 Προτάσεις εκχώρησης
assignment_operators.c |
---|
| #include <stdio.h>
int main() {
// Ανάθεση (=)
int a = 5;
printf("Assignment: a = %d\n", a);
// Έλεγχος ισότητας (==)
int b = 5;
if (a == b) {
printf("Equality: a == b is true\n");
} else {
printf("Equality: a == b is false\n");
}
// Από δεξιά προς τα αριστερά αποτίμηση
a = b = 7;
// Ανάθεση με πρόσθεση (+=), ομοίως για -=, *=, /=, %=
a += 10; // Ισοδύναμο με: a = a + 10;
printf("Addition Assignment: a += 10 -> a = %d\n", a);
// Τελεστής μοναδιαίας αύξησης (++)
int x = 3;
printf("Initial x = %d\n", x);
// Pre-increment (++x)
printf("Pre-increment: ++x = %d\n", ++x); // Πώτα αύξηση, μετά εκτύπωση
// Post-increment (x++)
printf("Post-increment: x++ = %d\n", x++); // Εκτύπωση πρώτα, μετά αύξηση
printf("After post-increment, x = %d\n", x);
return 0;
}
|
$ gcc assignment_operators.c && ./a.out
Assignment: a = 5
Equality: a == b is true
Addition Assignment: a += 10 -> a = 17
Initial x = 3
Pre-increment: ++x = 4
Post-increment: x++ = 4
After post-increment, x = 5
7.7.5 Η εκχώρηση ως έκφραση
assignment_as_expression.c |
---|
| #include <stdio.h>
int main() {
int sum = 0, num;
while ((num = 3)) {
sum += num;
if (sum > 10) break;
}
printf("Sum after loop: %d\n", sum);
return 0;
}
|
$ gcc assignment_as_expression.c && ./a.out
Sum after loop: 12
7.8 Αναθέσεις μεικτού-τύπου
mixed_types_assignments.py |
---|
| # Integer to float (widening)
i = 10
f = float(i) # Explicit conversion (optional, as Python allows direct assignment)
print(f"Widening: i (int) = {i}, f (float) = {f:.2f}")
# Float to int (narrowing)
pi = 3.14159
x = int(pi) # Explicit conversion, truncates decimal part
print(f"Narrowing: pi (float) = {pi}, x (int) = {x}")
# String to int (valid case)
s = "42"
num = int(s) # Converts string to integer
print(f"String to int: s = '{s}', num = {num}")
# Invalid string to int (error)
try:
invalid_s = "9"
num = int(invalid_s) # Will raise ValueError
except ValueError:
print(f"Cannot convert '{invalid_s}' to int!")
# Integer to string
n = 123
s = str(n) # Converts int to string
print(f"Int to string: n = {n}, s = '{s}'")
# Float to string
f = 99.99
s = str(f) # Converts float to string
print(f"Float to string: f = {f}, s = '{s}'")
# Boolean to int
b = True
num = int(b) # True → 1, False → 0
print(f"Boolean to int: b = {b}, num = {num}")
# Int to boolean
num = 0
b = bool(num) # 0 → False, nonzero → True
print(f"Int to boolean: num = {num}, b = {b}")
# Implicit conversion (int to float in expression)
result = 5 + 2.5 # Python automatically promotes int to float
print(f"Implicit conversion: 5 + 2.5 = {result} (type: {type(result)})")
|
$ python mixed_types_assignments.py
Widening: i (int) = 10, f (float) = 10.00
Narrowing: pi (float) = 3.14159, x (int) = 3
String to int: s = '42', num = 42
Int to string: n = 123, s = '123'
Float to string: f = 99.99, s = '99.99'
Boolean to int: b = True, num = 1
Int to boolean: num = 0, b = False
Implicit conversion: 5 + 2.5 = 7.5 (type: <class 'float'>)