Hoe Maak Ik Een Rekenmachine In C

C Rekenmachine Bouwer – Stapsgewijze Calculator

Hoe Maak Ik een Rekenmachine in C: Complete Gids

Het bouwen van een rekenmachine in C is een uitstekende manier om je programmeervaardigheden te verbeteren. Deze gids behandelt alles van basisrekenkunde tot geavanceerde wetenschappelijke functies, met praktische voorbeelden en beste praktijken.

1. Basisconcepten voor een C Rekenmachine

1.1 Vereiste Kennis

  • Basis C-syntaxis (variabelen, lussen, voorwaarden)
  • Functies en hun parameters
  • Pointers en geheugenbeheer
  • Basiswiskundige operaties

1.2 Benodigde Bibliotheken

Voor een basisrekenmachine heb je alleen stdio.h nodig. Voor geavanceerde functies:

#include <stdio.h>
#include <math.h>   // Voor sin, cos, log, etc.
#include <stdlib.h>  // Voor exit(), atof()

2. Stapsgewijze Implementatie

2.1 Eenvoudige Command-Line Rekenmachine

Begin met een programma dat twee getallen accept en een bewerking uitvoert:

#include <stdio.h>

int main() {
    char operator;
    double num1, num2;

    printf("Voer operator in (+, -, *, /): ");
    scanf("%c", &operator);

    printf("Voer twee getallen in: ");
    scanf("%lf %lf", &num1, &num2);

    switch(operator) {
        case '+':
            printf("%.2lf + %.2lf = %.2lf", num1, num2, num1 + num2);
            break;
        case '-':
            printf("%.2lf - %.2lf = %.2lf", num1, num2, num1 - num2);
            break;
        case '*':
            printf("%.2lf * %.2lf = %.2lf", num1, num2, num1 * num2);
            break;
        case '/':
            if(num2 != 0)
                printf("%.2lf / %.2lf = %.2lf", num1, num2, num1 / num2);
            else
                printf("Fout! Delen door nul.");
            break;
        default:
            printf("Ongeldige operator!");
    }

    return 0;
}

2.2 Geavanceerde Functies Toevoegen

Voeg wetenschappelijke functies toe met math.h:

#include <math.h>

// Voeg deze cases toe aan je switch statement
case 's':
    printf("sin(%.2lf) = %.2lf", num1, sin(num1));
    break;
case 'c':
    printf("cos(%.2lf) = %.2lf", num1, cos(num1));
    break;
case 't':
    printf("tan(%.2lf) = %.2lf", num1, tan(num1));
    break;
case 'l':
    printf("log(%.2lf) = %.2lf", num1, log(num1));
    break;

3. Geheugenbeheer en Pointers

3.1 Dynamisch Geheugen Gebruiken

Voor complexe rekenmachines met historische gegevens:

#include <stdlib.h>

typedef struct {
    double operand1;
    double operand2;
    char operation;
    double result;
} CalculationHistory;

CalculationHistory* history = NULL;
int historySize = 0;

void addToHistory(double op1, double op2, char op, double res) {
    historySize++;
    history = realloc(history, historySize * sizeof(CalculationHistory));
    history[historySize-1] = (CalculationHistory){op1, op2, op, res};
}

3.2 Best Practices voor Pointers

  • Controleer altijd op NULL na malloc/calloc
  • Gebruik altijd free() om geheugenleks te voorkomen
  • Overweeg smart pointers in C++ als je met complexe projecten werkt

4. Foutafhandeling en Validatie

4.1 Input Validatie

Voorkom crasht door onjuiste input:

if(scanf("%lf", &num1) != 1) {
    printf("Ongeldige input!\n");
    // Wis de input buffer
    while(getchar() != '\n');
    continue;
}

4.2 Veilige Berekeningen

Potentieel Probleem Oplossing Voorbeeld Code
Delen door nul Controleer noemer voor berekening if(denominator == 0) { /* fout */ }
Overflow/underflow Gebruik grotere datatypes long double voor grote getallen
Ongeldige operator Gebruik switch met default case default: printf("Ongeldig");
Geheugenlek Gebruik valgrind om te testen valgrind ./je_programma

5. Geavanceerde Onderwerpen

5.1 Grafische Interface met GTK

Voor een GUI-rekenmachine:

#include <gtk/gtk.h>

static void on_activate(GtkApplication* app) {
    GtkWidget *window = gtk_application_window_new(app);
    // Voeg hier je widgets toe
    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char **argv) {
    GtkApplication *app = gtk_application_new("org.example.calculator", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
    return g_application_run(G_APPLICATION(app), argc, argv);
}

5.2 Multithreading voor Complexe Berekeningen

Gebruik threads voor zware berekeningen:

#include <pthread.h>

void* calculate(void* arg) {
    // Zware berekening hier
    pthread_exit(NULL);
}

int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, calculate, NULL);
    pthread_join(thread, NULL);
    return 0;
}

6. Prestatie Optimalisatie

6.1 Compiler Optimalisaties

Gebruik GCC optimalisatie flags:

gcc -O3 -march=native -mtune=native je_programma.c -o calculator -lm
Optimalisatie Flag Beschrijving Prestatie Impact
-O0 Geen optimalisatie Basislijn
-O1 Basis optimalisaties 10-20% sneller
-O2 Extra optimalisaties 20-30% sneller
-O3 Agressieve optimalisatie 30-50% sneller (kan debuggen bemoeilijken)
-march=native Optimaliseer voor lokale CPU 5-15% extra

6.2 Inline Assembly voor Kritische Secties

Voor maximale prestaties in performance-kritische delen:

__asm__("fld %1;\n"
           "fld %2;\n"
           "faddp;\n"
           "fstp %0;"
           : "=m"(result)
           : "m"(num1), "m"(num2));

7. Testen en Debuggen

7.1 Unit Testing met Check

Gebruik het Check framework voor automatische tests:

#include <check.h>

START_TEST(test_addition) {
    ck_assert_double_eq(add(2, 3), 5);
}
END_TEST

Suite *calc_suite(void) {
    Suite *s = suite_create("Calculator");
    TCase *tc_core = tcase_create("Core");
    tcase_add_test(tc_core, test_addition);
    suite_add_tcase(s, tc_core);
    return s;
}

int main(void) {
    int number_failed;
    Suite *s = calc_suite();
    SRunner *sr = srunner_create(s);
    srunner_run_all(sr, CK_NORMAL);
    number_failed = srunner_ntests_failed(sr);
    srunner_free(sr);
    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

7.2 Debuggen met GDB

Essentiële GDB commando’s:

gcc -g je_programma.c -o calculator -lm
gdb ./calculator
break main
run
print variabele_naam
step
next
continue
quit

8. Implementatie Voorbeelden

8.1 Complete Basis Rekenmachine

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define MAX_INPUT 100

double performOperation(double a, double b, char op) {
    switch(op) {
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/':
            if(b == 0) {
                printf("Fout: Delen door nul!\n");
                exit(1);
            }
            return a / b;
        case '^': return pow(a, b);
        case 's': return sin(b * M_PI / 180); // Graden naar radialen
        case 'c': return cos(b * M_PI / 180);
        case 't': return tan(b * M_PI / 180);
        case 'l': return log(b);
        case 'q': return sqrt(b);
        default:
            printf("Ongeldige operator: %c\n", op);
            exit(1);
    }
}

int main() {
    char input[MAX_INPUT];
    double num1, num2;
    char op;

    printf("Wetenschappelijke Rekenmachine in C\n");
    printf("Gebruik: getal [operator] [getal]\n");
    printf("Voorbeelden:\n");
    printf("  5 + 3    (optellen)\n");
    printf("  10 - 4   (aftrekken)\n");
    printf("  2 ^ 8    (macht)\n");
    printf("  s 30     (sinus van 30 graden)\n");
    printf("  q 16     (vierkantswortel van 16)\n");

    while(1) {
        printf("\nVoer berekening in (of 'exit' om te stoppen): ");
        if(fgets(input, MAX_INPUT, stdin) == NULL) {
            printf("\nProgramma beëindigd.\n");
            break;
        }

        // Verwijder newline karakter
        input[strcspn(input, "\n")] = '\0';

        if(strcmp(input, "exit") == 0) {
            break;
        }

        // Parse input
        if(sscanf(input, "%lf %c %lf", &num1, &op, &num2) >= 3) {
            // Twee-operand bewerking
            double result = performOperation(num1, num2, op);
            printf("Resultaat: %.4lf\n", result);
        }
        else if(sscanf(input, "%c %lf", &op, &num2) >= 2) {
            // Eén-operand bewerking (wetenschappelijk)
            double result = performOperation(0, num2, op);
            printf("Resultaat: %.4lf\n", result);
        }
        else {
            printf("Ongeldige input. Probeer opnieuw.\n");
        }
    }

    return 0;
}

8.2 Rekenmachine met Geheugenfunctie

#include <stdio.h>
#include <stdlib.h>

double memory = 0.0;

void clearMemory() {
    memory = 0.0;
}

void addToMemory(double value) {
    memory += value;
}

void recallMemory(double *result) {
    *result = memory;
}

int main() {
    // ... (vorige code)

    // Voeg deze cases toe aan je switch statement
    case 'm':
        addToMemory(result);
        printf("Resultaat opgeslagen in geheugen (totaal: %.2lf)\n", memory);
        break;
    case 'r':
        recallMemory(&result);
        printf("Geheugenwaarde: %.2lf\n", result);
        break;
    case 'c':
        clearMemory();
        printf("Geheugen gewist\n");
        break;

    // ...
}

9. Veelgemaakte Fouten en Oplossingen

9.1 Drijvende Komma Nauwkeurigheid

Probleem: 0.1 + 0.2 ≠ 0.3 door binaire representatie

Oplossing: Gebruik een tolerantie bij vergelijkingen:

#define EPSILON 0.00001

if(fabs(a - b) < EPSILON) {
    // a en b zijn "gelijk"
}

9.2 Integer Overflow

Probleem: 2,000,000,000 + 2,000,000,000 = -294,967,296 (met int)

Oplossing: Gebruik grotere datatypes:

long long bigNumber1 = 2000000000;
long long bigNumber2 = 2000000000;
long long result = bigNumber1 + bigNumber2; // Correct: 4000000000

9.3 Verkeerde Operator Prioriteit

Probleem: result = a + b * c; vs result = (a + b) * c;

Oplossing: Gebruik altijd haakjes voor duidelijkheid:

result = (a + b) * c;

10. Bronnen voor Verdere Studie

Voor diepgaandere kennis over C-programmering en rekenmachine-implementaties:

11. Conclusie

Het bouwen van een rekenmachine in C is een uitstekende oefening die je helpt om:

  • Basis C-syntaxis onder de knie te krijgen
  • Foutafhandeling en input validatie te leren
  • Geheugenbeheer en pointers te begrijpen
  • Modulaire programmeertechnieken toe te passen
  • Prestatie optimalisaties te implementeren

Begin met een eenvoudige versie en breid geleidelijk uit met geavanceerde functies. Gebruik versiebeheer ( zoals Git) om je voortgang bij te houden en experimenteer met verschillende benaderingen om de beste oplossing voor je specifieke behoeften te vinden.

Onthoud dat de sleutel tot een goede rekenmachine ligt in:

  1. Robuuste input validatie
  2. Duidelijke foutmeldingen
  3. Efficiënte berekeningen
  4. Gebruiksvriendelijke interface
  5. Goede documentatie en comments

Met deze kennis kun je nu aan de slag om je eigen geavanceerde rekenmachine in C te bouwen!

Leave a Reply

Your email address will not be published. Required fields are marked *