Transcript C3_integers
Integers
נושאים:
קידוד מספרים שלמיםsigned & unsigned :
המשמעות לכתיבת תוכניות
...
C - חידות ב
סיביות32 מחשב מבוסס
ציין אם הוא נכון תמיד (עבור כל,C – עבור כל אחד מהביטויים הבאים ב
.)ערך
•
x < 0
•
ux >= 0
•
x & 7 == 7
•
ux > -1
•
x > y
unsigned ux = x;
•
x * x >= 0
unsigned uy = y;
•
x > 0 && y > 0
•
x >= 0
-x <= 0
•
x <= 0
-x >= 0
Initialization
int x = foo();
int y = bar();
–2–
((x*2) < 0)
(x<<30) < 0
-x < -y
x + y > 0
קידוד Integers
C תומך במספר הגדרות ל :Integers
יש הבדל בין ה'תקן' של ( Cמובטח לכל מהדר שתומך בתקן) לבין
מה שמהדרים ומחשבים תומכים בפועל.
מנצל רק 2
בתים מתוך 4
Intel IA32
טווח
4
-32768 ... 32767
4
0 ... 65535
4
-2,147,483,648 ... 2,147,483,647
4
0 ... 4,294,967,295
2
-32768 ... 32767
2
0 ... 63535
C Data Type
int
unsigned int
long int
unsigned long
short
unsigned short
( במחשבים מסוימים Intמנצל את כל ה 32סיביות)
––3
קידוד
כיצד נקודד מספר שלם בעזרת וקטור ביטים ?
תלוי אם הוא signed / unsigned
אם הוא unsignedהקידוד הוא פשוט המספר בבסיס 2
i
w 1
xi 2
) B 2U ( X
i0
Binary to
unsigned
––4
קידוד unsigned
המספר הנמוך ביותר שניתן לייצג:
000....0 = 0ומסומן ב UMin
המספר הגבוה ביותר שניתן לייצג:
111....1 = 2w-1ומסומן ב UMax
––5
קידוד signed
מספר אפשרויות קידוד .האפשרות הפשוטה ביותר :הסיבית
השמאלית מציינת אם המספר הוא חיובי או שלילי.
חסרונות:
ייצוג נפרד ל 0ול .-0
קשה יותר (יחסית לאלטרנטיבה שנראה) לבצע פעולות אריתמטיות
שונות.
האלטרנטיבה שרב המחשבים משתמשים בה נקראת
2’s complement
i
w2
xi 2
w 1
x w 1 2
) B 2T ( X
i0
Sign
Bit
Binary to
Two’s
complement
––6
מעבר ל 2-s complement
אם xהוא מספר חיובי ,אז ניתן לקבל את –xעל ידי .~x + 1
כך אכן מתקבל ש .x + -x = 0
דוגמה
x = 01100
כדי לקבל את –xתחילה נחשב את :~x
10011
עכשיו נוסיף :1
10100
אכן קיבלנו ש:
01100 +
10100
00000
––7
עם 2’s-complementקל יותר לחבר
בשיטת סיבית שמאלית = סיבית סימן:
x = 0101
0101+
-x = 1101
1101
חיבור פשוט ,פשוט לא עובד.
0010
בשיטת :2’s complement
x = 0101
0101+
-x = 1011
1011
0000
––8
דוגמה נוספת
;short int x = 15213
;short int y = -15213
Binary
00111011 01101101
11000100 10010011
Decimal
15213
-15213
x
y
סיבית הסימן מוסיפה מספר שלילי גדול )( -215 = -32768
––9
המשך דוגמה
x =
y =
W e ig h t
– 10 –
1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
-3 2 7 6 8
Sum
15213: 00111011 01101101
-15213: 11000100 10010011
15213
1
1
0
0
1
4
1
8
0
0
1
32
1
64
0
0
1
256
1
512
0
0
1
2048
1
4096
1
8192
0
0
0
0
15213
-1 5 2 1 3
1
1
1
2
0
0
0
0
1
16
0
0
0
0
1
128
0
0
0
0
1
1024
0
0
0
0
0
0
1
16384
1
-3 2 7 6 8
-1 5 2 1 3
קידוד signedעם 2’s complement
המספר הנמוך ביותר שניתן לייצג:
1000....0 = -2w-1ומסומן ב TMin
המספר הגבוה ביותר שניתן לייצג:
011....1 = 2w-1 -1ומסומן ב TMax
– – 11
ייצוג ערכים
? -1 מה הייצוג של: חידה
w = 16 ערכים עבור
UMax
TMax
TMin
-1
0
– 12 –
D e cim a l
65535
32767
-3 2 7 6 8
-1
0
Hex
FF FF
7F FF
80 00
FF FF
00 00
B in a ry
11111111 11111111
01111111 11111111
10000000 00000000
11111111 11111111
00000000 00000000
ערכי מינ'/מקס' משתנים עם רוחב המילה
W
64
1 8 ,4 4 6 ,7 4 4 ,0 7 3 ,7 0 9 ,5 5 1 ,6 1 5
9 ,2 2 3 ,3 7 2 ,0 3 6 ,8 5 4 ,7 7 5 ,8 0 7
-9 ,2 2 3 ,3 7 2 ,0 3 6 ,8 5 4 ,7 7 5 ,8 0 8
32
4 ,2 9 4 ,9 6 7 ,2 9 5
2 ,1 4 7 ,4 8 3 ,6 4 7
-2 ,1 4 7 ,4 8 3 ,6 4 8
כשכותבים תוכנית ב – : C
>#include <limits.h
מגדיר קבועים:
ULONG_MAX
LONG_MAX
LONG_MIN
16
6 5 ,5 3 5
3 2 ,7 6 7
-3 2 ,7 6 8
8
255
127
-1 2 8
U M ax
TM ax
T M in
נשים לב:
| TMax + 1= |TMin
טווח לא סימטרי
2 * TMax + 1 = UMax
ערכים אלה תלויים במחשב ובמהדר
– – 13
ערכים של signed & unsigned
אותו קידוד עבור מספרים לא-
שליליים.
כל וקטור ביטים מייצג מספר
שלם ייחודי ולהפך
)B2T(X
0
1
2
3
4
5
6
7
–8
–7
–6
–5
–4
–3
–2
–1
)B2U(X
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
X
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
– – 14
המרת טיפוס ( )Castingמ sig.ל uns.
המרת טיפוסים ב C -
short int
;x = 15213
;unsigned short int ux = (unsigned short) x
short int
;y = -15213
;unsigned short int uy = (unsigned short) y
תוצאה
הייצוג (וקטור הביטים) אינו משתנה!
ערכים חיוביים נשארים:
ux = 15213
מספרים שליליים משתנים למספרים חיוביים (גדולים):
uy = 50323
– – 15
המרת טיפוס ( )Castingמ sig.ל uns.
מה בעצם מתקבל ?
x 0
x 0
x
w
x 2
ux
0
+++
• • •
w–1
ux + + +
+++
• • •
x
-++
-
+2w–1 – –2w–1 = 2*2w–1 = 2w
ההבדל בערך
בגלל casting
הורד ערך שלילי
הוסף ערך חיובי
– – 16
uns לsig. ) מCasting( המרת טיפוס
W e ig h t
1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
Sum
-1 5 2 1 3
1
1
1
2
0
0
0
0
1
16
0
0
0
0
1
128
0
0
0
0
1
1024
0
0
0
0
0
0
1
16384
1
-3 2 7 6 8
-1 5 2 1 3
y + 65536=
– 17 –
50323
1
1
1
2
0
0
0
0
1
16
0
0
0
0
1
128
0
0
0
0
1
1024
0
0
0
0
0
0
1
16384
1
32768
50323
y + 2 * 32768= uy
Signed vs. Unsignedב C -
קבועים
כבררת מחדל נחשבים .signedניתן לסמנם כ unsאם מצמידים להם : u
0U, 4294967259U
המרות ()Casting
המרה מפורשת.
;ty
;uy
;ux
;ty
int tx,
unsigned ux,
)tx = (int
)uy = (unsigned
המרה לא מפורשת דרך השמות וקריאות לפונקציות:
;tx = ux
;uy = ty
– – 18
...הפתעות
ביטויים מעורבים
הופך להיותsigned ,)<, >, ==,...: בביטויים מעורבים (כולל פרדיקטים
Unsigned
W = 32 דוגמאות עבור
Constant1
Tmax
– 19 –
00
-1
-1
-1
-1
2147483647
2147483647
2147483647U
2147483647U
-1
-1
(unsigned) -1
-1
(unsigned)
2147483647
2147483647
2147483647
2147483647
Constant2
Relation Evaluation
0U
0U
00
Tmin
0U
0U
-2147483648
-2147483648
-2147483648
-2147483648
-2
-2
-2
-2
2147483648U
2147483648U
(int) 2147483648U
2147483648U
(int)
==
<
>
>
<
>
>
<
>
unsigned
signed
unsigned
signed
unsigned
signed
unsigned
unsigned
signed
הפתעות
אמת או שקר:
-1u > -2
מה הערך של ? -1u
נוכל לבדוק על ידי השורה הבאה:
) printf(“%u”,-1u
נסו בבית...
– – 20
הסבר
2’s Comp. Unsigned
מספר שלילי ==> מספר חיובי גבוה
TMax
2’s Comp.
Range
– 21 –
0
–1
–2
TMin
UMax
UMax – 1
TMax + 1
TMax
0
Unsigned
Range
)Sign Extension( הרחבה
המטרה
w + k ברוחבsigned int המר אותו ל,w ברוחבsigned int בהינתן
.שמייצג אותו ערך
:הכלל
sign bit עותקים של הk הוסף
X = xw–1 ,…, xw–1 , xw–1 , xw–2 ,…, x0
w
k copies of MSB
X
• • •
• • •
X
– 22 –
• • •
k
• • •
w
דוגמה להרחבה
short int x = 15213;
int
ix = (int) x;
short int y = -15213;
int
iy = (int) y;
x
ix
y
iy
Decimal
Hex
15213
3B
15213 00 00 3B
-15213
C4
-15213 FF FF C4
6D
6D
93
93
Binary
00111011
00000000 00000000 00111011
11000100
11111111 11111111 11000100
01101101
01101101
10010011
10010011
. מבצע הרחבות מסוג זה באופן אוטומטיC
– 23 –
נכונות
באינדוקציה על k
צעד האינדוקציה :נרחיב בסיבית אחת
w
• • •
-
• • •
- +
X
X
w+1
נשים לב–2w–1 = –2w +2w–1 :
נסתכל על המשקל של הסיביות החשובות (משמאל):
–2w–1 xw–1
=
–2w–1 xw–1
–2w xw–1 + 2w–1 xw–1
X
X
– – 24
חישובים :שלילה
טענה :השוויון הבא מתקיים ב :2’s complement
~x + 1 == -x
מדוע?
~x + x == 1111…112 == -1
1001 1101
x
0110 0010
+ ~x
1111 1111
-1
הוספה:
)== -1 + (-x + 1
== -x
)~x + x + (-x + 1
~x + 1
– – 25
דוגמאות
x = 15213
x
~x
~x+1
y
D e cim a l
15213
-1 5 2 1 4
-1 5 2 1 3
-1 5 2 1 3
Hex
3B 6D
C4 92
C4 93
C4 93
B in a ry
00111011 01101101
11000100 10010010
11000100 10010011
11000100 10010011
0
0
~0
~0+1
– 26 –
D e cim a l
0
-1
0
Hex
00 00
FF FF
00 00
B in a ry
00000000 00000000
11111111 11111111
00000000 00000000
unsigned חיבור ב
u
• • •
v
• • •
u+v
• • •
UAddw(u , v)
• • •
Operands: w bits
+
True Sum: w+1 bits
Discard Carry: w bits
'מימוש של 'אריתמטיקה מודולרית
u + v mod 2w=
UAdd
– 27 –
UAddw(u , v)= s
w (u, v )
u v
w
u v 2
uv2
w
uv2
w
חיבור ints
)Add4(u , v
Integer Addition
32
28
24
20
16
14
- u, vמשתנים בני 4
סיביות
הסכום האמיתי:
)Add4(u , v
התוצאה גדלה ליניארית
עם u v
יוצר 'משטח'
12
12
10
8
8
v
4
6
0
4
2
0
14
12
10
8
6
4
2
0
u
– – 28
כשהמשתנים הם unsigned
חוזר להתחלה...
גלישה
)UAdd4(u , v
אם הסכום האמיתי גדול
מ 2w
לא יותר מפעם אחת
16
14
12
גלישה
True Sum
2w+1
10
8
14
6
12
10
v
2w
4
8
2
6
0
4
2
0
14
12
10
8
6
4
2
0
סכום מודולרי
0
u
– – 29
תכונות מתמטיות
סגור תחת חיבור
0 UAddw(u , v) 2w –1
קומוטטיבי
UAddw(u , v) = UAddw(v , u)
אסוציאטיבי
UAddw(t, UAddw(u , v)) = UAddw(UAddw(t, u ), v)
0 - תפקידו של ה
UAddw(u , 0) = u
:קיים אלמנט משלים
UCompw (u ) = 2w – u
UAddw(u , UCompw (u )) = 0
Let
– 30 –
2’s Complement חיבור
u
• • •
v
• • •
u+v
• • •
TAddw(u , v)
• • •
Operands: w bits
+
True Sum: w+1 bits
Discard Carry: w bits
פועלות זהה ברמת הביטיםTAdd and UAdd
:C – חיבור ב
int s, t, u, v;
s = (int) ((unsigned) u + (unsigned) v);
t = u + v
s == t נקבל
– 31 –
אפיון של TAdd
)u + v < Tminw (NegOver
Tminw · u + v · Tmaxw
)u + v > Tmaxw (PosOver
u + v + 2w
u+v
u + v – 2w
= )Taddw(u,v
פונקציונאליות
הסכום האמיתי דורש w+1סיביות
הורד את ה MSB -
התייחס למה שנשאר כ intהמיוצג ב – 2’s complement
למשל :עבור w = 4מתקבל . -8 + -1 = 7
1000 +
1111
0111
– – 32
חיבור ב 2’s complement
NegOver
ערכים
)TAdd4(u , v
8
6
גלישה
4
0
6
-2
2
-4
0
-6
-2
v
-8
-4
-6
PosOver
-8
6
4
2
0
-2
-4
-6
-8
אם sum 2w–1
נהיה שלילי
לא יותר מפעם אחת
2
4
4סיביות
טווח :מ -8עד +7
אם sum < –2w–1
נהיה חיובי
לא יותר מפעם אחת
u
– – 33
? כיצד נזהה גלישה
מטרה
s = TAddw(u , v) בהינתן
s = Addw(u , v) קבע האם
דוגמה
int s, u, v;
s = u + v;
טענה
גלישה אם
u, v < 0, s 0 (NegOver)
u, v 0, s < 0 (PosOver)
ovf = (u<0 == v<0) && (u<0 != s<0);
– 34 –
מכפלה
טווחים
Unsigned: 0 ≤ x * y ≤ (2w – 1) 2 = 22w – 2w+1 + 1
Up to 2w bits
Two’s complement min: x * y ≥ (–2w–1)*(2w–1–1) = –22w–2 + 2w–1
Up to 2w–1 bits
Two’s complement max: x * y ≤ (–2w–1) 2 = 22w–2
Up to 2w bits, but only for (TMinw)2
. בשקף הבא: התוצאה.תיגרם גלישה
? 'כיצד נחשב 'בדיוק
דורש הקצאה דינמית של זיכרון
ישנן חבילות תוכנה לחישוב מדויק
(“arbitrary precision” arithmetic packages)
GNU Multiple Precision (GMP)
http://gmplib.org/
– 35 –
C - בunsigned מכפלה של
Operands: w bits
True Product: 2*w bits u · v
Discard w bits: w bits
*
u
• • •
v
• • •
• • •
• • •
• • •
UMultw(u , v)
מכפלה סטנדרטית
. הביטים משמאלw מתעלם מ
modular arithmetic למעשה מחשב מכפלה ב
u · v mod 2w= UMultw(u , v)
– 36 –
מכפלה של Signed
מכפלת מספרים המיוצגים ב 2’s complement
;int x, y
;int p = x * y
חשב תוצאת מכפלה של שני מספרים x,yברוחב .w
הורד ביטים משמאל עד קבלת תוצאה ברוחב p = TMultw(x, y) .w
(כלומר ,החישוב זהה למקרה הקודם)
– – 37
השוואה בין שני המקרים
Unsigned Multiplication
unsigned ux = (unsigned) x;
unsigned uy = (unsigned) y;
unsigned up = ux * uy
Two’s Complement Multiplication
int x, y;
int p = x * y;
היחס ביניהם
נותן בדיוק אותה תוצאה ברמת הביטים
up == (unsigned) p
:מתקיים היחס
– 38 –
shift עם2 מכפלה בחזקות של
נשים לב
u << k gives u * 2k
unsigned והן בsigned הן ב
Operands: w bits
True Product: w+k bits
*
u · 2k
u
k
• • •
2k
0 ••• 0 1 0 ••• 0 0
• • •
UMultw(u , 2k)
Discard k bits: w bits
TMultw(u , 2k)
u * 8
0 ••• 0 0
דוגמאות
==
u << 3
(u << 5) – (u << 3)
.add וshift ברוב המחשבים הכפלה איטית בהרבה לעומת
u * 24
– 39 –
•••
0 ••• 0 0
==
. בכוחות עצמוShift בדר"כ המהדר יודע לבצע את ההתמרה ל
Shift עם2 חלוקה בחזקות של
u >> k gives u / 2k
.0 לא כלפי,כלומר במספרים שליליים התוצאה תעוגל כלפי מטה
logical shift ולכן נשתמש בunsigned בדוגמה להלן נניח
k
u
Operands:
/
x
x >> 1
x >> 4
x >> 8
– 40 –
•••
0 •••
•••
u / 2k
0 •••
•••
Division
15213
7606.5
950.8125
59.4257813
10111 >> 1
Computed
15213
7606
950
59
-4.5
Binary Point
0 ••• 0 1 0 ••• 0 0
u / 2k
Division:
Result:
2k
•••
Hex
3B 6D
1D B6
03 B6
00 3B
-5 11011
.
•••
Binary
00111011 01101101
00011101 10110110
00000011 10110110
00000000 00111011
x = -9 עכשיו נניח
C - תשובות לחידות ב
int x = foo();
int y = bar();
unsigned ux = x;
.2’s complement סיביות וקידוד32 נניח מחשב עם
unsigned uy = y;
x < 0
ux >= 0
x & 7 == 7
ux > -1
x > y
x * x >= 0
x > 0 && y > 0
x >= 0
x <= 0
– 41 –
((x*2) < 0)
False:
TMin
True:
0 = UMin
True:
x1 = 1
False:
0
False:
-1, TMin
False:
30426
x + y > 0
False:
TMax, TMax
-x <= 0
True:
–TMax < 0
-x >= 0
False:
TMin
(x<<30) < 0
-x < -y
ביתר פרוט...
(x<<30) < 0
x & 7 == 7
מצד שמאל אנחנו יודעים 3 :הסיביות הימניות הן .1
אחרי הזזה שמאלה ב – 30מקומות ,ה sign-bitחייב להיות ,1כלומר מספר שלילי.
לדוגמה ,נניח .x = 15
האם מקיים ? x & 7 == 7
אחרי הזזה 30צעדים שמאלה11000000.....:
(קרוב ל )Tmin
– – 42
ביתר פרוט...
ux > -1
המרת טיפוס אוטומטית ל .unsigned
ייצוג של :-1
1111....111
אחרי המרה ל Umax :unsigned
4,294,967,295
כלומר התשובה היא לא :לא מתקיים .ux > -1
– – 43
ביתר פרוט...
-x <= 0
x >= 0
נזכור ש ||Tmax| < |Tmin
לכן כאן התשובה היא כן
-x >= 0
x <=0
וכאן יש לנו גלישה .לכן התשובה היא לא.
– – 44
מתי נשתמש ב ?Unsigned
לא להשתמש רק בגלל שאין צורך בשליליים!
קיימים מהדרי Cשזה גורם להם ליצור קוד פחות יעיל
קל לעשות טעויות (כפי שראינו!)
אז מתי כן להשתמש ב ?unsigned
כשצריך טווח גדול יותר של מספרים חיוביים
יישומים שונים מסתמכים על ( modular arithmeticמסתמכים על הערך
אחרי הגלישה)
לעתים משתמשים ב Intכאוסף של דגלים.
למשל ,קיבוץ של 6דגלים011001 :
פונקציות סטנדטיות לעתים מחזירות .unsignedלמשל )(( sizeמחזיר
size_tשזה בעצם .)unsigned
;vector v
;)(unsigned s = v.size
– – 45
?Unsigned מתי נשתמש ב
!לא להשתמש רק בגלל שאין צורך בשליליים
שזה גורם להם ליצור קוד פחות יעילC קיימים מהדרי
:קל לעשות טעויות
.1
float sum_elements(float a[], unsigned length) {
int i;
float result = 0;
for (i = 0; i <= length -1 ; i++)
result += a[i];
return result; }
.2
unsigned int i;
for (i = cnt-2; i >= 0; i--)
a[i] += a[i+1];
– 46 –