Grenzen der fundamentalen Datentypen - BFH

Werbung
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Eigenschaft der Fundamentalen
Java baut auf 8 fundamentalen Datentypen (primitiven) auf. Java
kann ausschliesslich mit diesen Primitiven rechnen! Für die
Arithmetik wird in Java zwischen zwei Rechenarten unterschieden:
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Eigenschaft der Fundamentalen
Java baut auf 8 fundamentalen Datentypen (primitiven) auf. Java
kann ausschliesslich mit diesen Primitiven rechnen! Für die
Arithmetik wird in Java zwischen zwei Rechenarten unterschieden:
Integer Rechnen mit ganzen Zahlen in vollständiger Präzision
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Eigenschaft der Fundamentalen
Java baut auf 8 fundamentalen Datentypen (primitiven) auf. Java
kann ausschliesslich mit diesen Primitiven rechnen! Für die
Arithmetik wird in Java zwischen zwei Rechenarten unterschieden:
Integer Rechnen mit ganzen Zahlen in vollständiger Präzision
Float Rechnen mit gebrochenen Zahlen in angenäherter Präzision
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Rechnen im Intervall
Dabei werden Datentypen verwendet, welche innerhalb eines
beschränkten Zahlenraums sämtliche ganze Zahlen darstellen
können:
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Fazit
Rechnen im Intervall
Dabei werden Datentypen verwendet, welche innerhalb eines
beschränkten Zahlenraums sämtliche ganze Zahlen darstellen
können:
Zahlenspiele
Typ
byte
short
int
long
Bit
8
16
32
64
Zahlenraum
256
65536
4294967296
18446744073709551616
Wertebereich
−128
−32768
−2147483648
−9223372036854775808
...
...
...
...
+127
+32767
+2147483647
+9223372036854775807
char
16
65536
+0
...
+65535
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Fazit
Rechnen im Intervall
Dabei werden Datentypen verwendet, welche innerhalb eines
beschränkten Zahlenraums sämtliche ganze Zahlen darstellen
können:
Zahlenspiele
Typ
byte
short
int
long
Bit
8
16
32
64
Zahlenraum
256
65536
4294967296
18446744073709551616
Wertebereich
−128
−32768
−2147483648
−9223372036854775808
...
...
...
...
+127
+32767
+2147483647
+9223372036854775807
char
16
65536
+0
...
+65535
Es wird offensichtlich, dass der Default-Wert int z.B. in der
heutigen Finanzwelt unzureichend ist, wie folgendes Beispiel
erläutert:
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Rechnen im Intervall
8
9
10
11
12
13
int val = Integer . MAX_VALUE ;
System . out . print ( " Gewinn der UBS im Jahr 2007: " ) ;
System . out . println ( val ) ; // -> 2147483647
val +=2;
System . out . print ( " Gewinn der UBS im Jahr 2008: " ) ;
System . out . println ( val ) ; // -> -2147483647
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Rechnen im Intervall
8
9
10
11
12
13
int val = Integer . MAX_VALUE ;
System . out . print ( " Gewinn der UBS im Jahr 2007: " ) ;
System . out . println ( val ) ; // -> 2147483647
val +=2;
System . out . print ( " Gewinn der UBS im Jahr 2008: " ) ;
System . out . println ( val ) ; // -> -2147483647
15
16
17
18
19
20
long val = Integer . MAX_VALUE ;
System . out . print ( " Gewinn der UBS im Jahr 2007: " ) ;
System . out . println ( val ) ; // -> 2147483647
val +=2;
System . out . print ( " Gewinn der UBS im Jahr 2008: " ) ;
System . out . println ( val ) ; // -> 2147483649
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
Dabei werden Datentypen verwendet, welche innerhalb eines
beschränkten Zahlenraums einige Reelle Zahlen darstellen können:
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
Dabei werden Datentypen verwendet, welche innerhalb eines
beschränkten Zahlenraums einige Reelle Zahlen darstellen können:
Zahlenspiele
Typ
float
double
Bit
32
64
Zahlenraum
4294967296
18446744073709551616
Wertebereich
±1, 4 × 10−45
±4, 9 × 10−324
...
...
±3, 4 × 1038
±1, 7 × 10308
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
Dabei werden Datentypen verwendet, welche innerhalb eines
beschränkten Zahlenraums einige Reelle Zahlen darstellen können:
Zahlenspiele
Typ
float
double
Bit
32
64
Zahlenraum
4294967296
18446744073709551616
Wertebereich
±1, 4 × 10−45
±4, 9 × 10−324
...
...
±3, 4 × 1038
±1, 7 × 10308
Um den Wertebereich von float vollständig in einer linearen
Granularität von 1, 4 × 10−45 darstellen zu können, bräuchte es
einen Zahlenraum der Grösse 2 × 101710 . Es wird offensichtlich,
dass mit einem Zahlenraum von 232 somit riesige Zahlenlöcher
entstehen, welche die Genauigkeit bis zum Unbrauchbaren
degradieren lassen, wie folgendes Beispiel erläutert:
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
22
23
System . out . println ( " Next double value after 1000:
" + Math . nextUp (1000 d ) ) ;
// -> 1 00 0. 00 00000000001
Fazit
Rechnen mit Java
Ganze Zahlen
Angenäherter Präzision
25
26
double val = 1.0 e16 ;
double add =1000;
Gebrochene Zahlen
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
25
26
27
double val = 1.0 e16 ;
double add =1000;
System . out . println ( " " + val + " + " + add + " -" + val + " = " +
( val + add - val ) ) ;
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
25
26
27
28
double val = 1.0 e16 ;
double add =1000;
System . out . println ( " " + val + " + " + add + " -" + val + " = " +
( val + add - val ) ) ;
// -> 1000.0
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
25
26
27
28
29
30
31
32
double val = 1.0 e16 ;
double add =1000;
System . out . println ( " " + val + " + " + add + " -" + val + " = " +
( val + add - val ) ) ;
// -> 1000.0
System . out . println ( " Next double value after " +
val + " : " + Math . nextUp ( val ) ) ;
// -> 1 .0 00 0000000000002 E16
System . out . println ( " Precise : " +( long ) ( Math .
nextUp ( val ) ) ) ;
// -> 100 00000000000002
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
34
35
36
37
38
39
40
41
double val = 1.0 e17 ;
double add =1000;
System . out . println ( " " + val + " + " + add + " -" + val + " = "
+( val + add - val ) ) ;
// -> 992.0
System . out . println ( " Next double value after " +
val + " : " + Math . nextUp ( val ) ) ;
// -> 1. 0 0 000000000000016 E17
System . out . println ( " Precise : " +( long ) ( Math .
nextUp ( val ) ) ) ;
// -> 1 00 000000000000016
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
43
44
45
46
47
48
49
50
double val = 1.0 e18 ;
double add =1000;
System . out . println ( " " + val + " + " + add + " -" + val + " = "
+( val + add - val ) ) ;
// -> 1024.0
System . out . println ( " Next double value after " +
val + " : " + Math . nextUp ( val ) ) ;
// -> 1. 0 0 000000000000013 E18
System . out . println ( " Precise : " +( long ) ( Math .
nextUp ( val ) ) ) ;
// -> 10 0 0 000000000000128
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
52
53
54
55
56
57
58
59
double val = 1.0 e19 ;
double add =1000;
System . out . println ( " " + val + " + " + add + " -" + val + " = "
+( val + add - val ) ) ;
// -> 0.0
System . out . println ( " Next double value after " +
val + " : " + Math . nextUp ( val ) ) ;
// -> 1 .0 00 0000000000002 E19
System . out . println ( " Precise : " +( long ) ( Math .
nextUp ( val ) ) ) ;
// -> 92 2 3 372036854775807
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
Der Wertebereich im Bereich ±0 ist somit am feinsten aufgelöst
und gibt somit das genauste Resultat. Man könnte annehmen,
dass eine Rechnung so nahe an 0 wie möglich sein sollte. . . aber
auch das stimmt leider nicht:
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
73
74
75
76
77
double val =100.0;
val /=3.0;
val /=3.0;
val *=9.0;
System . out . println ( " ((100/3.0) /3.0) *9.0 = " + val ) ;
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
73
74
75
76
77
78
double val =100.0;
val /=3.0;
val /=3.0;
val *=9.0;
System . out . println ( " ((100/3.0) /3.0) *9.0 = " + val ) ;
// -> 1 00 .0 00 00000000001
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
80
81
82
83
84
double val =100;
val *=9;
val /=3.0;
val /=3.0;
System . out . println ( " ((100*9) /3.0) /3.0 = " + val ) ;
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Angenäherter Präzision
80
81
82
83
84
85
double val =100;
val *=9;
val /=3.0;
val /=3.0;
System . out . println ( " ((100*9) /3.0) /3.0 = " + val ) ;
// -> 100.0
Fazit
Rechnen mit Java
Angenäherter Präzision
Ganze Zahlen
Gebrochene Zahlen
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
Es gibt in Java eine Möglichkeit, ’Fliesskoma-Zahlen’ mit beliebiger
Präzision zu verwalten. Diese Möglichkeit wird mit Hilfe der Klasse
BigDecimal erreicht. Dabei wird die darzustellende Zahl
’häppchenweise’ gerechnet. Damit scheint das Problem gelöst zu
sein:
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
88
89
90
BigDecimal val = new BigDecimal ( " 1.0 e19 " ) ;
BigDecimal add = new BigDecimal ( " 1000 " ) ;
System . out . println ( " " + val + " + " + add + " -" + val + " = " + (
val . add ( add ) . subtract ( val ) ) ) ;
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
88
89
90
91
BigDecimal val = new BigDecimal ( " 1.0 e19 " ) ;
BigDecimal add = new BigDecimal ( " 1000 " ) ;
System . out . println ( " " + val + " + " + add + " -" + val + " = " + (
val . add ( add ) . subtract ( val ) ) ) ;
// -> 1000.0
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
93
94
95
BigDecimal val = new BigDecimal ( " 1.0 e19 " ) ;
BigDecimal fraction = new BigDecimal ( " 1.0 e -19 " ) ;
System . out . println ( " " + val + " + " + fraction + " = " + (
val . add ( fraction ) ) ) ;
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
93
94
95
96
BigDecimal val = new BigDecimal ( " 1.0 e19 " ) ;
BigDecimal fraction = new BigDecimal ( " 1.0 e -19 " ) ;
System . out . println ( " " + val + " + " + fraction + " = " + (
val . add ( fraction ) ) ) ;
// -> 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 . 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
Fazit
Rechnen mit Java
Beliebiger Präzision
Ganze Zahlen
Gebrochene Zahlen
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
Aber leider klappt auch in diesem Falle das Rechnen mit
Rationalen Zahlen nicht:
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
98
99
100
101
102
BigDecimal val = new BigDecimal ( " 100.0 " ) ;
val = val . divide ( new BigDecimal ( " 3.0 " ) ) ;
val = val . divide ( new BigDecimal ( " 3.0 " ) ) ;
val = val . multiply ( new BigDecimal ( " 9.0 " ) ) ;
System . out . println ( " ((100/3.0) /3.0) *9.0 = " + val )
;
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
98
99
100
101
102
103
BigDecimal val = new BigDecimal ( " 100.0 " ) ;
val = val . divide ( new BigDecimal ( " 3.0 " ) ) ;
val = val . divide ( new BigDecimal ( " 3.0 " ) ) ;
val = val . multiply ( new BigDecimal ( " 9.0 " ) ) ;
System . out . println ( " ((100/3.0) /3.0) *9.0 = " + val )
;
// -> java . lang . ArithmeticException : Non terminating decimal expansion ; no exact
representable decimal result .
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
105
106
107
108
109
BigDecimal val = new BigDecimal ( " 100.0 " ) ;
val = val . divide ( new BigDecimal ( " 3.0 " ) ,20 ,
BigDecimal . ROUND_HALF_UP ) ;
val = val . divide ( new BigDecimal ( " 3.0 " ) ,20 ,
BigDecimal . ROUND_HALF_UP ) ;
val = val . multiply ( new BigDecimal ( " 9.0 " ) ) ;
System . out . println ( " ((100/3.0) /3.0) *9.0 = " + val )
;
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Beliebiger Präzision
105
106
107
108
109
110
BigDecimal val = new BigDecimal ( " 100.0 " ) ;
val = val . divide ( new BigDecimal ( " 3.0 " ) ,20 ,
BigDecimal . ROUND_HALF_UP ) ;
val = val . divide ( new BigDecimal ( " 3.0 " ) ,20 ,
BigDecimal . ROUND_HALF_UP ) ;
val = val . multiply ( new BigDecimal ( " 9.0 " ) ) ;
System . out . println ( " ((100/3.0) /3.0) *9.0 = " + val )
;
// -> 9 9 . 9 9 9 9 9 9 9 9 99 9 9 9 99 9 9 9 99 0
Fazit
Rechnen mit Java
Beliebiger Präzision
Ganze Zahlen
Gebrochene Zahlen
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Wir haben gesehen, dass das Rechnen mit den Primitiven
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Wir haben gesehen, dass das Rechnen mit den Primitiven
für ganze Zahlen innerhalb des Bereiches möglich ist
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Wir haben gesehen, dass das Rechnen mit den Primitiven
für ganze Zahlen innerhalb des Bereiches möglich ist
für gebrochene Zahlen nicht den Erwartungen entspricht
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Wir haben gesehen, dass das Rechnen mit den Primitiven
für ganze Zahlen innerhalb des Bereiches möglich ist
für gebrochene Zahlen nicht den Erwartungen entspricht
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Wir haben gesehen, dass das Rechnen mit den Primitiven
für ganze Zahlen innerhalb des Bereiches möglich ist
für gebrochene Zahlen nicht den Erwartungen entspricht
Es ist wichtig zu verstehen, dass dies kein Problem einer speziellen
Programmiersprache ist, sondern das Problem der
Computerarchitektur.
Fazit
Rechnen mit Java
Ganze Zahlen
Gebrochene Zahlen
Wir haben gesehen, dass das Rechnen mit den Primitiven
für ganze Zahlen innerhalb des Bereiches möglich ist
für gebrochene Zahlen nicht den Erwartungen entspricht
Es ist wichtig zu verstehen, dass dies kein Problem einer speziellen
Programmiersprache ist, sondern das Problem der
Computerarchitektur.
Aber
In Java gibt es die Möglichkeit Klassen zu schreiben, welche die
rationale Mathematik exakt abbilden.
Fazit
Herunterladen