Programmieren
 
 
 
 
 
C-Grundkurs
 
 
 
 
 
.. Beispiel: Body-Mass-Index
 
 

 
 
 
 
 
Aufgabe:
Schreiben Sie eine C -Funktion, welche den Body-Mass-Index (BMI) berechnet. Die Funktion soll bei Fehlübergaben den Wert bmi=0 zurückgeben.

Theorie:
Der Body-Mass-Index setzt das Gewicht einer Person mit ihrer Körpergröße in Beziehung. Hierbei gelten je nach Lebensalter, bestimme Bereiche des Körpergewichts als normal, über- oder untergewichtig, wie die nachfolgenden Tabellen zeigen. Die dargestellten Tabellen geben einen Anhalt für Durchschnittsmenschen, also nicht für z.B. Sportler oder Schwerstarbeiter und sind wie alle generalisierenden Aussagen mit Bedacht zu betrachten.

Formel:
Der Body-Mass-Index berechnet sich aus dem Körpergewicht [kg] dividiert durch das Quadrat der Körpergröße [m2]. Die Formel lautet entsprechend ..
                                                 BMI = Körpergewicht : (Körpergröße in m)2
                                                 Die Einheit des BMI ist demnach kg/m2.

Der wünschenswerte BMI hängt vom Alter ab. Die folgende Tabelle zeigt BMI-Werte für verschiedene Altersgruppen und Einschätzungen zum Körpergewicht, unterschieden nach männlichen und weiblichen Personen ..
 
 
 
 

 

Alter
BMI in kg/m²
 

 

 

 

19-24 Jahre
19-24
 

 

 

 

25-34 Jahre
20-25
 

 

 

 

35-44 Jahre
21-26
 

 

 

 

45-54 Jahre
22-27
 

 

 

 

55-64 Jahre
23-28
 

 

 

 

>64 Jahre
24-29
 

 

 

 

 
 
 

 

 

 

 
Männlich BMI=
Weiblich BMI=
Klassifikation

 

 

 
<20
<19
Untergewicht

 

 

 
20-25
19-24
Normalgewicht

 

 

 
25-30
24-30
Übergewicht

 

 

 
30-40
30-40
Adipositas

 

 

 
>40
>40
massive Adipositas

 

 
 
 
 
 
 
 
1. Lösung
Sie benutzt das Fliesskommaformat double für das Gewicht und die Körpergröße. Zudem verhindert sie eine Division durch 0, indem Körpergrößen kleiner gleich 0 ausgeschlossen werden. Da übergroße Menschen ohnehin bezüglich des BMI gesondert betrachtet werden müssen, wurde auch die Eingabe von Größen über 2,55 Metern ausgeschlossen. Die Funktion gibt in beiden Fällen einen BMI von 0 zurück. Es wäre zu überlegen, ob auch unsinnige Gewichtsangaben zu begrenzen wären. Allerdings behindern sie nicht die Resultate der Funktion.
 
 

 
// bmi.cpp
// --------------  Version 10.04.2010
//                 IPC@CHIP: Fliesskommaemulation ein
//                 D.Schwarzer, www.GoBlack.de

// Thema: Body-Mass-Index nach der Formel bmi= m/l*l berechnen.
// Es werden die Fliesskommaemulation oder ein Fließkommaprozessor
// benötigt


// Headerdateien der IDE
#include <conio.h>
#include <stdio.h>


// fbmi()
// berechnung des BMI im Fliesskommaformat. Bei einer Grössenangabe
// von 0 oder kleiner und bei solchen größer als 3m gibt die
// Funktion 0 zurück
double fbmi (double masse, double groesse)
{
  if(groesse<=0 || groesse>2.55)return(0);
  return(masse /(groesse*groesse));
}


// main()
// Testprogramm mit festen Vorgaben für Gewicht und Körpergröße
void main(void)
{
  double gewicht = 80;
  double laenge  = 1.77;
  double bmi     = 0;

  bmi= fbmi(gewicht, laenge);
  printf("\r\n bei einer Groesse von: %5.2fm"
         "\r\n und einem Gewicht von: %5.2fkg"
         "\r\n betraegt der Body-Mass-Index = %5.2fkg/m^2",
         laenge, gewicht, bmi);
  getch();
}
 

 
 
 
 
 
2. Lösung:
Die zweite Lösung geht davon aus, dass für den benutzten Prozessor keine Fließkommaarithmetik bereitsteht, also im Bereich Ganzer Zahlen gearbeitet werden muss. Gewicht und Körpergröße werden der Funktion also als Ganze Zahlen übergeben. Im einfachsten Fall bedingt dies, dass die Körpergröße in cm anzugeben ist, und für das Gewicht nur ganze Kilogramm angegeben werden können.

    Überlegungen
  • Da bei der Ganzzahlarithmetik keine Nachkommastellen auftreten, muss die in kg angegebene Masse mit dem Faktor 100*100 multipliziert werden, denn die Körpergröße wird ja um den Faktor 100 vergrößert übergeben um dann quadriert zu werden. Dies überfordert Speicherzellen vom Typ unsigned, es sei denn, man will nur Gewichte unter 6 kg angeben. (6*100*100 = 60 000 (max.unsigned 65535)).
  • Das vorhergehende Problem lässt sich durch einen Speicher vom Typ long umgehen. Dieser kann Werte bis 232 : 2 => -2 147 483 648 bis +2 147 483 647 aufnehmen, so dass der Mensch zusammen mit der nachfolgenden Überlegung noch ein Gewicht von 2147kg haben dürfte.
  • Man erhält nun wieder einen ganzzahligen BMI der jedoch keine 'Nachkommastellen' beinhaltet. Eine weitere Multiplikation mit 100 würde es später möglich machen, 2 Nachkommastellen zu isolieren, denn durch die letzte Multiplikation wäre das Ergebnis um 100 zu groß.
  • Die Quadratbildung der Körpergröße funktioniert in einem Speicher vom Typ unsigned nur bis 255, denn 256*256=35536 ist bereits um 1 zu groß für diesen Speichertyp. Allerdings könnte man dieses Problem umgehen, wenn man zwei mal durch die Körpergröße teilt, denn z : (p • p) = z : p : p.
 
 

 

 

// bmi.cpp
// --------------  Version 10.04.2010
//                 IPC@CHIP: Fliesskommaemulation aus
//                 D.Schwarzer, www.GoBlack.de

// Thema: Body-Mass-Index nach der Formel bmi= m/l*l berechnen.
// Alle Berechnungen im Ganzzahlformat


// Headerdateien der IDE
#include <conio.h>
#include <stdio.h>


// gbmi()
// berechnung des BMI im Ganzzahlformat und um den Faktor 100, zum
// Erhalt zweier Nachkommastellen, zu groß. Die Multiplikation der
// Masse mit 100*100 berücksichtigt die Angabe der Körpergröße
// in cm.
// Rückgabe:
//  0, bei Übergaben der Körpergrösse kleiner gleich 0
//     und größer als 2,55m (da 255*255 = 65025 max. unsigned)
//     deswegen besser Möglichkeit 2 (=> beliebige Längenangaben) 
unsigned gbmi (unsigned masse, unsigned groesse)
{
  long m=((long)masse)*100*100 * 100;
  if(groesse<=0 || groesse>255)return 0;
  //  return((unsigned)(m /(groesse*groesse)));  // 1. Möglichkeit
  return((unsigned)(m / groesse / groesse));     //    .. besser
}


// main()
// Testprogramm mit festen Vorgaben für Gewicht und Körpergröße. Es
// ist hier die Zerlegung des BMI in einen Vorkomma- und einen
// Nachkommaanteil zu beachten. Beide werden durch ein Komma
// getrennt, einzeln ausgegeben
void main(void)
{
  unsigned gewicht = 80;
  unsigned laenge  = 177;
  unsigned bmi= 0, bmivk=0, bmink=0;

  bmi= gbmi(gewicht, laenge);     // Berechnung des BMI*100
  bmivk=bmi / 100;                // Vorkommaanteil isolieren
  bmink=bmi % 100;                // Nachkommaanteil isolieren

  printf("\r\n bei einer Groesse von: %3.0dcm"
         "\r\n und einem Gewicht von: %3.0dkg"
         "\r\n betraegt der Body Mass Index = %2.0d,%0.2dkg/m^2",
         laenge, gewicht, bmivk, bmink);
  getch();
}

 

 

 
 
 
 
 
Verwendete Operatoren

/     - Divisionsoperator
Bei Ganzen Zahlen ergibt sich ein ganzzahliges Ergebnis ohne Nachkommastellen. Letztere werden abgeschnitten.

%  - Modulodivision
Bei Ganzen Zahlen stellt das Ergebnis den Rest der durchgeführten Division dar.

||    - logisches ODER
Der Ausdruck if (groesse<=0 || groesse>255) return 0; bedeutet also .. wenn (groesse kleiner,gleich 0 ist ODER groesse größer als 255 ist) dann .. beende die Funktion und kehre mit dem Wert 0 zurück.

(long)   - Typkonversion
long m=((long) masse)* 100*100 * 100;
Da der Speicher mit dem Namen masse vom Typ unsigned ist, würde die CPU nur zwei Bytes für die Berechnung von masse•100•100•100 verwenden, was in den meisten Fällen zu einem falschen Ergebnis führen würde. Die Typkonversion nach (long) des unsigned Speichers mit Namen masse bewirkt, dass die CPU 4 Bytes für die nachfolgende Berechnung benutzt.
Das Ergebnis wird der Speicherzelle m übergeben, die natürlich auch vom Typ long sein muss.

(unsigned)   - Typkonversion
return((unsigned)(m / groesse / groesse));
Da die Funktion einen Wert vom Typ unsigned zurückgeben soll das Ergebnis aber in einem Speicher vom Typ long abgelegt wurde, wird hier eine Typwandlung nach unsigned angewiesen. Dies ist möglich, da das Ergebnis nie 65535 überschreiten wird und zudem eine Warnung des Compilers unterbunden wird, der mitbekommt, dass ein long-Wert auf unsigned verkürzt wird.

%0.2d   -Formatierungsanweisung von printf() bei der Ganzzahlrechnung
Der BMI ist bei der Ganzzahlrechnung um den Faktor 100 zu groß. So können folgend zwei 'Nachkommastellen' isoliert werden. Diese liegen nach der Modulo-Berechnung (bmi%100) im Bereich zwischen 0 und 99 vor. Damit Reste im Bereich 0-9 als 09 und nicht als 9 ausgegeben werden, wurde die prinft-Formatierungsanweisung %0.2d benutzt. Diese bewirkt die Ausgabe von .2 Ziffern im Ausgabefeld, wobei eventuell fehlende Stellenangaben mit führenden Nullen 0. aufgefüllt werden. So werden die Reste von 0-9 zu 00-09. s.auch printf() in der C-Bibliothek.
 
 

 
 
 
 
 
 
 
 
3. Lösung mit Tastatureingabe
Die letzte Lösung ermöglicht die Eingabe der Körpergröße und des Gewichts bei laufendem Programm. Hierzu muss die Headerdatei fstrgin.h eingebunden werden, denn die in ihr enthaltene Funktion fstrgin() ermöglicht die Eingabe von der Tastatur. Die das Programm umgebende while()-Schleife kann durch einen Druck auf die ESC-Taste nach jeder Berechnung unterbrochen werden, womit auch das Programm endet.
Das Programm arbeitet sowohl auf PC-Rechnern als auch auf solchen mit dem IPC@CHIP-Baustein.

Allerdings muss bei den IPC-Rechnern die Eingabe von der Tastatur auf das BMI-Programm gelenkt werden, da sie andernfalls nur das Betriebssystem erreicht (multitask). Dies gelingt mit einer Funktion, welche bei IPC den Eingabekanal umschalten kann. Unten besitzt die Funktion den Namen stdio() und wird einmal am Anfang benutzt und zum Zurückschalten auf das Betriebssystem ebenfalls am Ende des Programms.
 
 

 
 
// bmi.cpp
// --------------  Version 10.04.2010
//                 IPC@CHIP: Fliesskommaemulation aus
//                 D.Schwarzer, www.GoBlack.de

// Thema: Body-Mass-Index nach der Formel bmi= m/l*l berechnen.
// Alle Berechnungen im Ganzzahlformat mit Eingabe der Größen


// Headerdateien der IDE
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>

// eigene Headerdatei für Tastatureingaben
#include "fstrgin.h"
                               //  fstrgin.h zum Kopieren ansehen


// gbmi()
// berechnung des BMI im Ganzzahlformat und um den Faktor 100, zum
// Erhalt zweier Nachkommastellen, zu groß. Die Multiplikation der
// Masse mit 100*100 berücksichtigt die Angabe der Körpergröße
// in cm.
// Rückgabe:
//  0, bei Übergaben der Körpergrösse kleiner gleich 0
//     und größer als 2,55m
unsigned gbmi (unsigned masse, unsigned groesse)
{
  long m=((long)masse)* 100*100 * 100;
  if(groesse<=0 || groesse>255)return 0;
  return((unsigned)(m / groesse / groesse));
}

// setStdio() nur für IPC@CHIP Bausteine
//            bei PC-Computern nicht aufrufen
// schaltet den Ein-/Ausgabestrom des IPC Webserver dem Parameter
// kanal entsprechend auf ..
//           RTOS Ein Aus  Benutzerprogramm Ein Aus
// kanal =1        x  x                      -   -
// kanal =2        -  -                      x   x
// kanal =3        x  x                      -   x     Vorgabe

void setStdio (char kanal)
{
   asm{ mov AH, 11h                 // SoftINT: A0h, Fkt: 11h
        mov AL, kanal
        int 0A0h      }
}

// main()
// Testprogramm mit festen Vorgaben für Gewicht und Körpergröße. Es
// ist hier die Zerlegung des BMI in einen Vorkomma- und einen
// Nachkommaanteil zu beachten. Beide werden durch ein Komma
// getrennt, einzeln ausgegeben. Das Programm kann nach einer
// Berechnung durch einen Druck auf die Taste [ESC] unterbrochen
// werden.
void main(void)
{
  // setStdio(2);         // IPC@CHIP -Eingaben zum eigen.Programm
  unsigned gewicht = 0;
  unsigned laenge  = 0;
  unsigned bmi= 0, bmivk=0, bmink=0;
  char txtbuf[10], c=0;

  while(c!= ESC){
   printf("\r\nGewicht in kg= ");        // Eingabeaufforderung
   fstrgin(txtbuf, 3, DEZ,"");           // Gewicht, 3 Dez-Stellen
   gewicht= atoi(txtbuf);                // in Integer wandeln

   printf("\r\nKoerpergroesse in cm= "); // Eingabeaufforderung
   fstrgin(txtbuf, 3, DEZ,"");           // Gewicht, 3 Dez-Stellen
   laenge= atoi(txtbuf);                 // in Integer wandeln


   bmi= gbmi(gewicht, laenge);         // Berechnung des BMI*100
   bmivk=bmi / 100;                    // Vorkommaanteil isolieren
   bmink=bmi % 100;                    // Nachkommaanteil isolieren

   printf("\r\n bei einer Groesse von: %3.0dcm"
          "\r\n und einem Gewicht von: %3.0dkg"
          "\r\n betraegt der Body Mass Index = %2.0d,%0.2dkg/m^2"
          "\r\n\n Ende [ESC], weiter [bel.Taste] ..",
          laenge, gewicht, bmivk, bmink);

   c=getch();
   printf ("\r\n\n");
  }
  // setStdio(3);         // IPC@CHIP -Eingaben zum Betriebssystem
}
 
 

 
 
 
 
www..de