Násobení čísel „pod sebou“ (jazyk C)

Tohle byl původně jeden z úkolů na ČVUT. Jen jsem si mírně upravil zadání pro vlastní potřebu a vyšel z toho takový pěkný prográmek. Bylo to skvělé cvičení v programování. Nic moc extra, ale hezky jsem se s tím pobavil, a chci se tedy pochlubit výsledkem.
Cílem úkolu bylo procvičit práci s poli v jazyku C. Výstup programuvypadá například takhle:

nasobeni

Stáhnout můžete zde: nasobeni.c.

/*******************************************************************************
 *                                                                             *
 *                            NASOBENI CISEL                                   *
 *                                                                             *
 *                Graficka simulace nasobeni dvou cisel                        *
 *                                                                             *
 *                       Jiri Rohan Leden 2012                                 *
 *******************************************************************************
 
 Jednotliva cisla nacitam jako retezce, abych mohl nasobit i skutecne velka
 cisla. Nezajimam se tak o preteceni datovych typu, nasobim a scitam cisla
 maximalne v radu desitek. Pozor si musim davat jen na velikost poli a
 spravnemu adresovani jejich prvku.
 
 Cisla v poli numbers[][] jsou ulozena pozpatku, cili sloupec 0 jsou jednotky,
 sloupec 1 jsou desitky, sloupec 2 stovky... Je to kvuli finalnimu scitani.
 Proste az vynasobim prvni cislo jednotlivymi cislicemi z druheho, a ziskam tak
 radu nezivysledku, proste jen sectu cisla v jednotlivych sloupcich.
 Po radcich jsou tam ulozena postupne od 0 vyse cisla A, B, mezivypocty a
 nakonec vysledek celeho nasobeni.
 
 O vypis na obrazovku se stara funkce printAll(). Teprve v ni resim jestli ma
 byt radek posunut doleva ci doprava, aby byla cisla zarovnana pod sebe atd.
 */

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

#define MAX_NUMBER_LENGTH 100
#define NUMBER_A 0
#define NUMBER_B 1
#define OTHER    3

int getLastDigit(long long int number);
void printLine(int len);
void countSemiResults(int numbers[MAX_NUMBER_LENGTH][MAX_NUMBER_LENGTH],
                      int* lines, int linesLen[MAX_NUMBER_LENGTH]);
int getLen(int number[MAX_NUMBER_LENGTH]);
void countResult(int numbers[MAX_NUMBER_LENGTH][MAX_NUMBER_LENGTH],
                 int *lines, int linesLen[MAX_NUMBER_LENGTH]);
void printEqRow(int line[MAX_NUMBER_LENGTH], int len, int number);
void printAll(int numbers[MAX_NUMBER_LENGTH][MAX_NUMBER_LENGTH],
              int lines, int linesLen[MAX_NUMBER_LENGTH],
              int positiveA, int positiveB);
void reverseFieldData(int number[MAX_NUMBER_LENGTH], int len);
int checkForZero(int number[MAX_NUMBER_LENGTH], int len);
int readInput(int number[MAX_NUMBER_LENGTH], int* positive);

int getLastDigit(long long int number)
{
	double lastDigit, num;
	lastDigit = modf(number/10.0, &num);
	return floor(lastDigit * 10 + 0.5);
}
void printLine(int len)
{
	int i;
    for (i = 0; i < len; i++)
		printf("-");
	printf("\n");
}

void countSemiResults(int numbers[MAX_NUMBER_LENGTH][MAX_NUMBER_LENGTH],
                      int* lines, int linesLen[MAX_NUMBER_LENGTH])
{
	int* numberA = numbers[NUMBER_A];
	int* numberB = numbers[NUMBER_B];
	int* semiResult = 0;

	int numberALength = linesLen[0];
	int numberBLength = linesLen[1];

	int idxB = 0, idxA = 0, tmp = 0;

	while (idxB < numberBLength)
	{
        semiResult = numbers[idxB + 2];
		while (idxA < numberALength || tmp != 0)
		{
			if (numberB[idxB] == 0)
				break;

            semiResult[idxA] = idxA < numberALength ? getLastDigit(numberB[idxB] * numberA[idxA] + tmp) : tmp;
            tmp = (numberB[idxB] * numberA[idxA] + tmp) / 10;
            idxA++;
            linesLen[*lines]++;
		}

        idxA = 0;
        (*lines)++;
		idxB++;
	}
}

int getLen(int number[MAX_NUMBER_LENGTH])
{
    int res = MAX_NUMBER_LENGTH - 1;

    while (number[res] == 0)
        res--;

    return res;
}

void countResult(int numbers[MAX_NUMBER_LENGTH][MAX_NUMBER_LENGTH],
                 int *lines, int linesLen[MAX_NUMBER_LENGTH])
{
	int idxRow, j, row = 2, column = 1;
	int length = linesLen[NUMBER_A] >= linesLen[NUMBER_B] ? linesLen[NUMBER_A] : linesLen[NUMBER_B];
    length += *lines;

	int number = 0;

	while (column < length || number > 0)
	{
		for (j = 0, idxRow = row; j < column && idxRow > 1; j++, idxRow--)
		{
			if (idxRow >= *lines)
			    continue;

			number += numbers[idxRow][j];
		}
		numbers[*lines][column - 1] = getLastDigit(number);
		number = (number - getLastDigit(number)) / 10;
		linesLen[*lines]++;
		row++;
		column++;
	}

    (*lines)++;
    linesLen[*lines -1] = getLen(numbers[*lines - 1]);
}

void printEqRow(int line[MAX_NUMBER_LENGTH], int len, int number)
{
	int idx, printSpace = 1;

	if (number == NUMBER_B)
	{
    	printf(" X ");
		len -= 3;
	}

	for (idx = 1; idx <= len; idx++)
	{
		if (line[len - idx] == 0 && printSpace == 1)
   		{
       		if (line[len - idx - 1] != 0 && line[0] < 0)
    		{
				printf("-");
				line[0] *= -1;
				continue;
    		}
       		printf("");
			continue;
		}
		else
			printSpace = 0;

		printf("%d", line[len - idx]);
	}
    printf("\n");
}

void printAll(int numbers[MAX_NUMBER_LENGTH][MAX_NUMBER_LENGTH], int lines,
              int linesLen[MAX_NUMBER_LENGTH], int positiveA, int positiveB)
{
	int i, charactersCount;
	int shift = 5;

	charactersCount = linesLen[lines - 1] + shift;

    numbers[NUMBER_A][0] *= positiveA;
    numbers[NUMBER_B][0] *= positiveB;
    numbers[lines - 1][0] *= (positiveA * positiveB);

	printEqRow(numbers[NUMBER_A] , charactersCount, NUMBER_A);
    printEqRow(numbers[NUMBER_B] , charactersCount, NUMBER_B);

    printLine(charactersCount);

	if (linesLen[NUMBER_B] == 1)
	{
		printEqRow(numbers[lines - 1], charactersCount, OTHER);
	    return;
	}

	for (i = 2; i < lines - 1; ++i)
	{
		if (linesLen[i] != 0)
            printEqRow(numbers[i] , charactersCount, OTHER);

		if (i >1)
		    charactersCount--;
	}

	charactersCount = linesLen[lines - 1] + shift;
	printLine(charactersCount);
	printEqRow(numbers[lines - 1], charactersCount, OTHER);
}

void reverseFieldData(int number[MAX_NUMBER_LENGTH], int len)
{
	int i, tmp;
	for (i = 0; i < len / 2; i++)
	{
		tmp = number[i];
		number[i] = number[len - 1 - i];
		number[len - 1 - i] = tmp;
	}
}

int checkForZero(int number[MAX_NUMBER_LENGTH], int len)
{
	int i;
	for (i = 0; i < len; i++)
	{
		if (number[i] != 0)
	    	return len;
	}
	return 1;
}

int readInput(int number[MAX_NUMBER_LENGTH], int* positive)
{
	int idx = 0;
	int c;
	int continueReadingDontSave = 0;
	*positive = 1;

	while ((c = getchar())!= '\n')
	{
		if (idx == MAX_NUMBER_LENGTH || continueReadingDontSave)
			continue;

  		if (c == '-')
		{
			if (idx > 0)
			{
			    continueReadingDontSave = 1;
			    continue;
			}
            (*positive) *= -1;
            continue;
		}

		if (isdigit(c))
		{
      		number[idx++] = c - 48;
      		continue;
		}
		if (isalpha(c) || (idx > 0 && !isdigit(c)))
			continueReadingDontSave = 1;
	};

 	reverseFieldData(number, idx);
	idx = checkForZero(number, idx);
    return idx;
}

int main(int argc, char *argv[])
{
    int numbers[MAX_NUMBER_LENGTH][MAX_NUMBER_LENGTH];
    int linesLen[MAX_NUMBER_LENGTH];
	int lines = 2;
	int positiveA  = 1, positiveB  = 1;

	printf("=========================\n");
	printf("==== Nasobeni cisel =====\n");
	printf("=========================\n");

	printf("Zadejte cislo A : ");
	linesLen[NUMBER_A] = readInput(numbers[NUMBER_A], &positiveA);

	printf("Zadejte cislo B : ");
	linesLen[NUMBER_B] = readInput(numbers[NUMBER_B], &positiveB);

	if (linesLen[NUMBER_A] == 0 || linesLen[NUMBER_B] == 0)
	{
	    printf("Chybny vstup.\n");
	    return 0;
	}

    printf("\n");

	countSemiResults(numbers, &lines, linesLen);
	countResult(numbers, &lines, linesLen);	
    printAll(numbers, lines, linesLen, positiveA, positiveB);

    return 0;
}
Příspěvek byl publikován v rubrice Programování se štítky , . Můžete si uložit jeho odkaz mezi své oblíbené záložky.