Forum: Compiler & IDEs Rechnen in C


von Besucher (Gast)


Lesenswert?

Hallo ins Forum

Ich hab ein Problem mit der Matrix multiplikation in C: bei der eingabe 
der ersten Matrix wird der Wert 3. Zeile 3. Spalte nicht abgefragt, bei 
der zweiten passt alles. Woran liegt der Fehler ?

Vielen Dank für die Hilfe
1
#include <stdio.h>
2
#include <conio.h>
3
 
4
 
5
int main(void)
6
{
7
float a[3][3],b[3][3],c[3][3], matrix;
8
int i,j,k;
9
 
10
printf("\n erste Matrix:");
11
for(i=1;i<=3;i++)
12
{
13
    for(j=1;j<=3;j++)
14
    {
15
        printf("\n %d. Zeile und %d. Spalte : ", i,j);
16
        scanf("%f",&matrix);
17
        a[i][j]=matrix;
18
    }
19
}
20
printf("\n zweite Matrix:");
21
 
22
for(i=1;i<=3;i++)
23
{
24
    for(j=1;j<=3;j++)
25
    {
26
        printf("\n %d. Zeile und %d. Spalte : ", i,j);
27
        scanf("%f",&matrix);
28
        b[i][j]=matrix;
29
    }
30
}
31
  for(i=1;i<=3;i++)
32
  {
33
    for(j=1;j<=3;j++)
34
    {
35
     
36
      c[i][j] = 0;  
37
      for(k=1;k<=3;k++)
38
      {
39
      c[i][j]+=a[i][k]*b[k][j];
40
      }
41
    printf("\nc[%d][%d]=%f", i,j,c[i][j]);
42
    }
43
  }
44
45
return 0;
46
}

: Bearbeitet durch User
von Stefan S. (chiefeinherjar)


Lesenswert?

Ein Array das 3 Elemente enthält wird mit 0..2 indexiert und nicht, wie 
bei dir, 1..3.
Du liest also als vermeintlich erste Spalte die zweite aus, anstatt der 
zweiten die dritte und bei der dritten liest du irgendwas aus dem RAM.

: Bearbeitet durch User
von Wayne (Gast)


Lesenswert?

Array fangen in C bei 0 an, nicht bei 1.
D.h. du musst zum Beispiel den Index 'i' mit 0 initialisieren: 
"for(i=0;i<3;i++)"

von Besucher (Gast)


Lesenswert?

Danke für den Tipp

bei Printf zeigt er dann 0. Zeile und 0. Spalte an.....was kann man tun 
?

printf("\n %d. Zeile und %d. Spalte : ", i,j)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Besucher schrieb:
> bei Printf zeigt er dann 0. Zeile und 0. Spalte an.....was kann man tun
> ?

Einfach 1 addieren:
1
printf("\n %d. Zeile und %d. Spalte : ", i+1, j+1)

von Walter T. (nicolas)


Lesenswert?

Ich würde übrigens Matrix-Rechnung grundsätzlich in doppelter 
Genauigkeit implementieren. Einfache Genauigkeit kann schon bei 
moderaten Konditionszahlen zu Fehler-Akkumulation führen, bei der man 
sich später den Wolf nach Implementierungsfehlern sucht.

Viele Grüße
W.T.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Einige Compiler weisen auf den Fehler hin. So z.B GCC bei einer
Optimierungsstufe >0:

1
...
2
test.c:17:16: warning: iteration 2 invokes undefined behavior [-Waggressive-loop-optimizations]
3
         a[i][j]=matrix;
4
         ~~~~~~~^~~~~~~
5
test.c:13:5: note: within this loop
6
     for(j=1;j<=3;j++)
7
     ^~~

von Rolf M. (rmagnus)


Lesenswert?

Walter T. schrieb:
> Ich würde übrigens Matrix-Rechnung grundsätzlich in doppelter
> Genauigkeit implementieren.

Empfohlen wird, generell immer double zu nehmen, wenn man keinen 
besonderen Grund hat, das nicht zu tun.

von Walter T. (nicolas)


Lesenswert?

Rolf M. schrieb:
> Empfohlen wird, generell immer double zu nehmen, wenn man keinen
> besonderen Grund hat, das nicht zu tun.

Auf einer 64-Bit-Plattform mit 64-Bit-FPU stimme ich Dir uneingeschränkt 
zu.

Auf einer 32-Bit-Plattform würde ich das nach dem Einzelfall abwägen. 
Bei numerisch stabilen Systemen (z.B. einem eindimensionalen Regler) 
spricht viel dafür, die native Bitbreite zu nutzen.

Bei Systemen, bei denen Matrizenrechnung erforderlich ist, neigt man 
allerdings dazu, erst einmal jede Menge "Library"-Funktionen zu 
schreiben, wenn man nicht schon auf eine fertige Library (z.B. LAPACK 
oder BLAST) zurückgreifen kann. Und fast zwangsläufig stößt man dann 
irgendwann auf eine Bedingung (schlechte Konditionierung), bei der 
normale Genauigkeit einen Rangabfall erzeugt, wo mit doppelter 
Genauigkeit noch genügend Sicherheitsmarge vorhanden gewesen wäre. Viel 
Spaß beim Suchen. BDDT.

von Rolf M. (rmagnus)


Lesenswert?

Walter T. schrieb:
> Rolf M. schrieb:
>> Empfohlen wird, generell immer double zu nehmen, wenn man keinen
>> besonderen Grund hat, das nicht zu tun.
>
> Auf einer 64-Bit-Plattform mit 64-Bit-FPU stimme ich Dir uneingeschränkt
> zu.
>
> Auf einer 32-Bit-Plattform würde ich das nach dem Einzelfall abwägen.
> Bei numerisch stabilen Systemen (z.B. einem eindimensionalen Regler)
> spricht viel dafür, die native Bitbreite zu nutzen.

Ok, bei einem µC muss man natürlich die Möglichkeiten der spezifischen 
Hardware mit in Betracht ziehen. Ich hatte jetzt irgendwie nur an den PC 
gedacht.

von Barrex (Gast)


Lesenswert?

Es ist so gar noch schlimmer Rolf. :-)

Auf einen Mikrocontroller ohne Gleitkomma-Unit würde ich nur mit integer 
also mit Festkommazahlen arbeiten. :-P

von Peter D. (peda)


Lesenswert?

Barrex schrieb:
> Auf einen Mikrocontroller ohne Gleitkomma-Unit würde ich nur mit integer
> also mit Festkommazahlen arbeiten. :-P

Das kann man nicht generell sagen. Es kommt darauf an, wie schnell und 
genau die Regelung sein muß. Ich habe gemerkt, daß eine Regelung ohne 
float sehr leicht ungenau wird (Rundungsfehler) oder übersteuert.
Float muß auch nicht viel langsamer als int sein. Man spart sich ja die 
ständigen Skalierungen ein, die bei int für hohe Genauigkeit nötig sind.

von PittyJ (Gast)


Lesenswert?

Barrex schrieb:
> Auf einen Mikrocontroller ohne Gleitkomma-Unit würde ich nur mit integer
> also mit Festkommazahlen arbeiten. :-P

Ich muss einmal pro Sekunde einen Winkel auf einem Arm-M0 ohne FPU 
berechnen. Dafür nehme ich die Emulation, das ist immer noch schnell 
genug.
Sowas hat früher selbst ein C64 locker gemacht.

Es kommt immer auf den Anwendungsfall an.

von WichtigTip (Gast)


Lesenswert?

Benutz einen Debugger und verstehe was dein Code macht!

von M.K. B. (mkbit)


Lesenswert?

WichtigTip schrieb:
> Benutz einen Debugger und verstehe was dein Code macht!

Ja!
Und vorher schaltet man am besten im Compiler noch ein hohes 
Warninglevel ein. Damit könnten (müssen aber nicht) solche und auch 
andere Fehler erkannt werden.

: Bearbeitet durch User
von Sebastian S. (amateur)


Lesenswert?

Ich wundere mich darüber, dass es keinen Meckerer zur Laufzeit gab. 
Schließlich wurde nicht nur eine Zeile [0] übergangen, sondern auch mit 
einer nicht existenten Zeile [3] gerechnet. Sprich in nicht reservierten 
Speicher gegrabscht.

von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Das kann man nicht generell sagen. Es kommt darauf an, wie schnell und
> genau die Regelung sein muß. Ich habe gemerkt, daß eine Regelung ohne
> float sehr leicht ungenau wird (Rundungsfehler) oder übersteuert.

Dann war sie beschissen umgesetzt.

> Float muß auch nicht viel langsamer als int sein. Man spart sich ja die
> ständigen Skalierungen ein, die bei int für hohe Genauigkeit nötig sind.

So ein grenzdebiler Blödsinn. Der Funktionsmechanismus von 
Gleitkommatypen beruht doch gerade darauf, ständig Skalierungen 
anzuwenden. Was natürlich zu ganz genau denselben Problem führt, nur 
weniger kontrollierbar, als wenn man das selber abhandelt (und dabei 
natürlich so viele Bits verwendet, wie sie auch das float-Format 
bietet).

Dann kann man nämlich exakt steuern, wann man die Größenordnung (in 
float also: den Exponenten) wechselt und ist nicht auf die überhaupt 
nicht an das konkrete Problem angepaßten Entscheidungen der float-lib 
angewiesen.

Float ist was für Leute, die zu faul sind, selber zu denken und die zu 
faul sind, selber Mathematik zu implementieren.

Der Vorteil von Float ist: es ist für viele Anwendungsfälle gut und 
schnell genug. Der Nachteil von Float ist: es ist praktisch immer 
suboptimal bezüglich der Laufzeit.

von S. R. (svenska)


Lesenswert?

c-hater schrieb:
> Der Vorteil von Float ist: es ist für viele Anwendungsfälle gut und
> schnell genug. Der Nachteil von Float ist: es ist praktisch immer
> suboptimal bezüglich der Laufzeit.

Das hängt von der Hardware ab. Auf aktuellen ARM-Prozessoren (und damit 
meine ich jetzt die dicke Ausführung für Android) ist Float-Arithmetik 
meistens schneller als Integer-Arithmetik.

Java- oder Javascript-Programmierer machen nämlich nur 
Double-Arithmetik, und deren Code stellt die Mehrheit dessen, was auf 
diesen CPUs läuft. Folgerichtig wird dort massiv Silizium investiert.

von user (Gast)


Lesenswert?

S. R. schrieb:
> c-hater schrieb:
>> Der Vorteil von Float ist: es ist für viele Anwendungsfälle gut und
>> schnell genug. Der Nachteil von Float ist: es ist praktisch immer
>> suboptimal bezüglich der Laufzeit.
>
> Das hängt von der Hardware ab. Auf aktuellen ARM-Prozessoren (und damit
> meine ich jetzt die dicke Ausführung für Android) ist Float-Arithmetik
> meistens schneller als Integer-Arithmetik.
>
> Java- oder Javascript-Programmierer machen nämlich nur
> Double-Arithmetik, und deren Code stellt die Mehrheit dessen, was auf
> diesen CPUs läuft. Folgerichtig wird dort massiv Silizium investiert

Git es dafür Beweise?
Warum sollte man in Java Double verwenden?
Bei Finanz-Berechnungen will man keine Fließkommazahlen verwenden!

von S. R. (svenska)


Lesenswert?

user schrieb:
> Warum sollte man in Java Double verwenden?

a) Weil es kein "Float" gibt.
b) Weil man öfter mit Kommazahlen rechnet.
c) Weil Finanz-Berechnungen für Android weniger relevant sind.

Und in Javascript gibt es ohnehin keinen anderen Datentyp.

von Commodore (Gast)


Lesenswert?

Der C64 mit seinem 6502-Abkömmling, hat Matrizen auch ohne Double 
berechnet!
Mit ordentlicher Pivotisierung sogar ganz genau!


Denkt mal drüber nach!

von Walter T. (nicolas)


Lesenswert?

Commodore schrieb:
> Mit ordentlicher Pivotisierung sogar ganz genau!
>
> Denkt mal drüber nach!

Wenn Pivotisierung in jedem Fall ausreichte, um einem Rangabfall 
vorzubeugen, hätte man doppelte Genauigkeit nie benötigt.

Denk mal drüber nach!

von asdf (Gast)


Angehängte Dateien:

Lesenswert?

asdf

von Rolf M. (rmagnus)


Lesenswert?

S. R. schrieb:
> user schrieb:
>> Warum sollte man in Java Double verwenden?
>
> a) Weil es kein "Float" gibt.

Das scheint Java noch gar nicht zu wissen, dass es das nicht hat:
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

von S. R. (svenska)


Lesenswert?

Commodore schrieb:
> Denkt mal drüber nach!

Auf einem C64 läuft kein Android.

von Commodore (Gast)


Lesenswert?

> Auf einem C64 läuft kein Android.

Besser ist das!

von (prx) A. K. (prx)


Lesenswert?

Walter T. schrieb:
> Auf einer 32-Bit-Plattform würde ich das nach dem Einzelfall abwägen.

Es besteht keinerlei Zusammenhang zwischen dem, was man gemeinhin als 
32-Bit Plattform bezeichnet, und der Arbeitsweise der FPU hinsichtlich 
32 und 64 Bits Fliesskommarechnung.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.