Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #define NEWLINE std::cout << std::endl
- #define MAX(x, y) ((x > y) ? x : y)
- void *ec_realloc(void *ptr, unsigned int size)
- {
- void *new_ptr;
- new_ptr = realloc(ptr, size);
- if (!new_ptr) {
- printf("[Error] ec_realloc(): realloc() returned NULL.");
- exit(-1);
- }
- return new_ptr;
- }
- void *ec_malloc(unsigned int size)
- {
- return ec_realloc(NULL, size);
- }
- /* Returns the char if found in string otherwise returns 0.
- * Dependency of strto_arrnumber
- */
- unsigned int strchr_(char *s, char c)
- {
- while (*s && *s != c) { s++; }
- return *s;
- }
- char *cin_getline()
- {
- char *string;
- /* i - used for *iterating* over the block s points to. */
- unsigned int i = 0, size = 100;
- /* Allocate memory for string */
- string = (char *)ec_malloc(size);
- for (
- int c;
- /* *While* c != EOF ^ '\n'. */
- EOF != (c = getchar()) && '\n' != c;
- /* *Insert* c into string. */
- *(string + i) = c, i++
- )
- {
- /* Resize string to fit the current chr ^ more chrs. */
- if (i >= size) {
- string = (char *)ec_realloc(string, (size += 30));
- }
- }
- /* Discard unused memory (also needed *if* i == size). */
- string = (char *)ec_realloc(string, i + 1);
- /* End string. */
- *(string + i) = '\0';
- return string;
- }
- /* Converts a string to array of numbers.
- * Returns null if conversion failed and sets errno_.
- * Ends array with 'E', to be used for calculating length with arrnumber_len.
- */
- int *strto_arrnumber(const char *string)
- {
- if (NULL == string || !*string) {
- printf("[Warning] strto_arrnumber(): Null input.\n");
- return NULL;
- }
- int *strnumber = (int *)malloc((strlen(string) + 1) * sizeof(int));
- /* Used for iterating over string. */
- unsigned int strI = 0;
- /* Used for forming strnumber. */
- unsigned int numI = 0;
- char white_space[] = " \n\t";
- /* Skip inital white space. */
- while (strchr_(white_space, string[strI])) {
- strI++;
- }
- /* Check for sign. */
- if (string[strI] == '-') {
- strnumber[numI++] = string[strI++];
- }
- else if (string[strI] == '+') {
- strI++;
- }
- /* If input string is null OR if input string contains only a sign (+ or -). */
- if (!string[strI]) {
- printf("[Warning] strto_arrnumber(): Please provide a number: %c[0-9].\n", string[strI - 1]);
- return NULL;
- }
- /* Ignore insegnificant zeorous */
- while (string[strI + 1] && string[strI] == '0') {
- strI++;
- }
- while (string[strI]) {
- /* If string[i] is a digit. */
- if (string[strI] >= '0' && string[strI] <= '9') {
- strnumber[numI++] = string[strI++] - '0';
- }
- else if (strchr_(white_space, string[strI])) {
- /* Ignore white space after the number. */
- while (strchr_(white_space, string[strI])) {
- strI++;
- }
- if (string[strI]) {
- printf("[Error] A number has no white space.\n");
- return NULL;
- }
- }
- /* string[i] is not a digit. */
- else {
- printf("[Error] Conversion failed: NaN.\n");
- return NULL;
- }
- }
- strnumber[numI] = 'E';
- return strnumber;
- }
- /* Work together with the output of strto_arrnumber */
- unsigned long arrnumber_len(int *strnumber)
- {
- unsigned int len = 0;
- while (*strnumber != 'E') {
- len++;
- strnumber++;
- }
- return len;
- }
- /* Shift array and fill (fill = 0) for positive offset, for negative shift and delete. */
- template <class type>
- unsigned int arrnshift(type [], unsigned int, unsigned int, int);
- /* From startingIndex until len, shift array and fill (fill left of startingI that is).
- * If startingIndex is >= len, fill from len until len + offset.
- */
- template <class type>
- unsigned int arrnfill(type [], unsigned int len, unsigned int startingI, int offset, type fill);
- /* Shift array and delete. If startingI >= len, changes nothing and returns len. */
- template <class type>
- unsigned int arrnshrink(type [], unsigned int, unsigned int, int);
- /* Compares two arrnumbers (their modoule!). */
- template <class type>
- int arrnumber_cmp(type[], type[], unsigned int, unsigned int);
- /* Copies int arrDest, offset elements from arrStr, begining with the startingI. */
- template <class type>
- unsigned int arrncpy(type arrDest[], type arrSrc[], unsigned int len, unsigned int startingI, int offset);
- /* Add two arrays, in a base < 10. */
- unsigned int arradd(int[], int[], unsigned int, unsigned int, unsigned int);
- /* Sub two arrays, in a base < 10. */
- unsigned int arrsub(int[], int[], unsigned int, unsigned int, unsigned int);
- /* Borrow when subbing. */
- int arrborrow(int[], unsigned int, unsigned int);
- /* Multiply two arrays, in a base < 10. */
- unsigned int arrmultiply(int termA[], int termB[], unsigned int lenA, unsigned int lenB, unsigned int base);
- int init()
- {
- char *string;
- string = cin_getline();
- char *token = NULL;
- char white_space[] = " \t\n";
- /* LEFT operand */
- int *operandA = NULL;
- if (NULL == (token = strtok(string, white_space))) { // get token
- puts("[Error] Please provide a left operand.");
- return -1;
- }
- if (NULL == (operandA = strto_arrnumber(token))) { // token to arrnumber
- printf("[Error] Invalid left operand: \"%s\".\n", token);
- return -1;
- }
- /* Operation */
- char op = 0;
- if (NULL == (token = strtok(NULL, white_space))) { // get token
- puts("[Error] Please provide an operation.");
- return -1;
- }
- char operations[] = "+-*";
- if (strlen(token) == 1) {
- if (!(op = strchr_(operations, *token))) { // get operator
- printf("[Error] Undefined operation: %s\n", token);
- return -1;
- }
- }
- else {
- puts("[Error] Please provide valid operation.");
- return -1;
- }
- /* RIGHT operand */
- int *operandB = NULL;
- if (NULL == (token = strtok(NULL, white_space))) { // get token
- puts("[Error] Please provide a right operand.");
- return -1;
- }
- if (NULL == (operandB = strto_arrnumber(token))) { // token to arrnumber
- printf("[Error] Invalid right operand: \"%s\".\n", token);
- return -1;
- }
- /* Check arity. */
- if (NULL != (token = strtok(NULL, white_space))) {
- return -1;
- }
- unsigned int lenA, lenB;
- lenA = arrnumber_len(operandA);
- lenB = arrnumber_len(operandB);
- /* Make sure the blocks of memory termA and termB point at
- * are big enough for all the operations.
- */
- operandA = (int *)ec_realloc(operandA, (lenA + lenB + 1) * sizeof(int));
- operandB = (int *)ec_realloc(operandB, (lenA + lenB + 1) * sizeof(int));
- unsigned int result_len = 0;
- if (op == '+') {
- result_len = arradd(operandA, operandB, lenA, lenB, 10);
- }
- else if (op == '-') {
- result_len = arrsub(operandA, operandB, lenA, lenB, 10);
- }
- else if (op == '*') {
- result_len = arrmultiply(operandA, operandB, lenA, lenB, 10);
- }
- /* Print result */
- unsigned int i = 0;
- if (operandB[i] > 10) {
- printf("%c", operandB[i++]);
- }
- for (; i < result_len; i++) {
- printf("%d", operandB[i]);
- }
- NEWLINE;
- free(operandA);
- free(operandB);
- free(string);
- return 0;
- }
- int main()
- {
- int ret;
- if ((ret = init())) {
- puts("\n[Usage] [+-]0-9 +,-,* [+-]0-9: <number> <operation> <number>.");
- }
- return ret;
- }
- /* Find sign; return 1 for '+', -1 for '-' and 0 for not found. */
- template <class type>
- int find_sign(type term[])
- {
- if (term[0] == '-') {
- return -1;
- }
- else if (term[0] == '+') {
- return 1;
- }
- // no sign
- return 0;
- }
- unsigned int arrsub(int termA[], int termB[], unsigned int lenA, unsigned int lenB, unsigned int base)
- {
- /* Find sign, if any. (1 for +, -1 for -, 0 for not found.) */
- int signA = find_sign(termA);
- int signB = find_sign(termB);
- // Skip sign OR set sign to 1 if no sign was found.
- unsigned int termA_1st_digit, termB_1st_digit;
- termA_1st_digit = termB_1st_digit = 0;
- if (signA) {
- termA_1st_digit++;
- }
- else {
- signA = 1;
- }
- if (signB) {
- termB_1st_digit++;
- }
- else {
- signB = 1;
- }
- /* Find the order relation between termA and termB. */
- int order = arrnumber_cmp(termA, termB, lenA, lenB);
- // -a - b = - (a + b) a - -b = a + b
- if (((signA == -1) && (signB == 1)) || ((signA == 1) && (signB == -1))) {
- if (signA == -1) {
- if (termB_1st_digit == 0) {
- lenB = arrnshift(termB, lenB, termB_1st_digit, 1);
- }
- termB[0] = '-';
- }
- else {
- arrnshift(termB, lenB, 0, -1);
- lenB--;
- }
- return arradd(termA, termB, lenA, lenB, base);
- }
- // -a - (-b) = -a + b
- else if (signB == -1) {
- signB = 1;
- }
- // The remaining calculation: a - b = a + (-b)
- else {
- signB = -1;
- }
- /* So there's either (-a + b) OR (a + (-b)) to calculate */
- /*[Obs] The next statemates make sure that the smaller number is the negative number
- * and if any signs are changed, set result_sign accordingly.
- */
- int result_sign = 0;
- /* Subbing numbers equal in module => 0. */
- if (!order) {
- termB[0] = 0;
- return 1;
- }
- /*If a > b AND -a + b to calculate; then flip signs: a + (-b). */
- else if (order > 0 && (signA == -1)) {
- result_sign = signA; // Set result_sign = sign of the greater number (a > b).
- signA = 1;
- signB = -1;
- }
- /*Elif a < b AND a + (-b) to calculate; then flip signs: -a + b */
- else if (order < 0 && (signB == -1)) {
- result_sign = signB; // Set result_sign = sign of the greater number (b > a).
- signA = -1;
- signB = 1;
- }
- /* If termB (which will store the result) is smaller than termA. */
- if (
- (lenB - termB_1st_digit) < (lenA - termA_1st_digit)
- )
- {
- /* Shift termB, starting at the first digit. */
- lenB = arrnshift<int>(termB, lenB, termB_1st_digit, lenA - lenB);
- }
- /* Operate */
- int iA, jB;
- iA = lenA - 1;
- jB = lenB - 1;
- int sum;
- sum = 0;
- /* Right to left do signed addition. */
- while (
- iA >= (int)termA_1st_digit &&
- jB >= (int)termB_1st_digit
- )
- {
- sum = termA[iA] * signA + termB[jB] * signB;
- if (sum < 0) {
- // Borrow from the positive number.
- if (signA == 1) {
- sum += arrborrow(termA, iA, base);
- }
- else {
- sum += arrborrow(termB, jB, base);
- }
- }
- termB[jB] = sum;
- iA--; jB--;
- }
- /* Count insegnificant zeros. */
- int offset = termB_1st_digit;
- while (offset < (int)lenB && !termB[offset]) {
- offset++;
- }
- offset -= termB_1st_digit;
- /* Delete insegnificant zeros, if any. */
- lenB = arrnshift<int>(termB, lenB, termB_1st_digit, -offset);
- /* If signs were changed apply result_sign. */
- if (result_sign == -1) {
- if (termB_1st_digit > 0) {
- termB[0] = '-';
- }
- else {
- lenB = arrnfill<int>(termB, lenB, 0, 1, (int)'-');
- }
- }
- else if (termB_1st_digit > 0) { // (Pozitive result) If termB has sign remove it.
- lenB = arrnshift(termB, lenB, 0, -1);
- }
- return lenB;
- }
- int arrborrow(int arr[], unsigned int poz, unsigned int base)
- {
- int i, found;
- i = poz - 1; // The next position to look for borrow.
- found = 0; // Whether there is "lender" to borrow from.
- /* Find "lender" right to left and borrow, if possible. */
- for (; i >= 0 && !found; i--) {
- if (arr[i] && arr[i] < (int)base) {
- arr[i]--;
- found = 1;
- }
- }
- /* No "lender". */
- if (!found) {
- return -1;
- }
- /* Else lender was found, and borrowed from "it". */
- /* Distribute the borrow, left to right. */
- for (i += 2; i < (int)poz; i++) {
- arr[i] += base - 1;
- }
- /* The borrower gets full unit. */
- arr[i] += base;
- return base;
- }
- unsigned int arradd(int termA[], int termB[], unsigned int lenA, unsigned int lenB, unsigned int base)
- {
- /* Find sign, if any. (1 for +, -1 for -, 0 for not found.) */
- int signA = find_sign(termA);
- int signB = find_sign(termB);
- // Skip sign OR set sign to 1 if no sign was found.
- unsigned int termA_1st_digit, termB_1st_digit;
- termA_1st_digit = termB_1st_digit = 0;
- if (signA) {
- termA_1st_digit++;
- }
- else {
- signA = 1;
- }
- if (signB) {
- termB_1st_digit++;
- }
- else {
- signB = 1;
- }
- /* If signs are different, return call arrsub. */
- if (signA != signB) {
- if (signA == -1) {
- /* -a + b = -a - (-b) */
- lenB = arrnfill<int>(termB, lenB, 0, 1, (int)'-');
- return arrsub(termA, termB, lenA, lenB, base);
- }
- else {
- /* a + (- b) = a - b */
- lenB = arrnshift<int>(termB, lenB, 0, -1);
- return arrsub(termA, termB, lenA, lenB, base);
- }
- }
- /* If termB (which will store the result) is smaller than termA. */
- if (
- (lenB - termB_1st_digit) < (lenA - termA_1st_digit)
- )
- {
- /* Shift termB, starting at the first digit. */
- lenB = arrnshift<int>(termB, lenB, termB_1st_digit, lenA - lenB);
- }
- /* Operate */
- int iA, jB;
- /* Used for iterating. */
- iA = lenA - 1;
- jB = lenB - 1;
- int sum, transport;
- sum = transport = 0;
- /* Right to left add. */
- while (
- iA >= (int)termA_1st_digit &&
- jB >= (int)termB_1st_digit
- )
- {
- sum = termA[iA] + termB[jB] + transport;
- termB[jB] = sum % (int)base;
- transport = (sum >= (int)base) ? 1 : 0; // t = (sum - termB[i]) / base;
- iA--; jB--;
- }
- /* While transport & there's more of termB (term[jB]-isDigit) add transport. */
- while (jB >= (int)termB_1st_digit && transport) {
- sum = termB[jB] + transport;
- termB[jB] = sum % (int)base;
- transport = (sum >= (int)base) ? 1 : 0;
- jB--;
- }
- /* If there's transport: shift by 1, starting at the index of 1st_digit
- * and fill new position with 1 (transport);
- */
- if (transport) {
- arrnfill<int>(termB, lenB, termB_1st_digit, 1, (int)transport);
- lenB++;
- }
- return lenB;
- }
- unsigned int arrmultiply(int termA[], int termB[], unsigned int lenA, unsigned int lenB, unsigned int base)
- {
- /* Find sign, if any. (1 for +, -1 for -, 0 for not found.) */
- int signA = find_sign(termA);
- int signB = find_sign(termB);
- // Skip sign OR set sign to 1 if no sign was found.
- unsigned int termA_1st_digit, termB_1st_digit;
- termA_1st_digit = termB_1st_digit = 0;
- if (signA) {
- termA_1st_digit++;
- }
- else {
- signA = 1;
- }
- if (signB) {
- termB_1st_digit++;
- }
- else {
- signB = 1;
- }
- /* 0 * ... */
- if ((lenA - termA_1st_digit) == 1 && termA[termA_1st_digit] == 0) {
- termB[0] = 0;
- return 1;
- }
- /* ... * 0 */
- if ((lenB - termB_1st_digit) == 1 && termB[termB_1st_digit] == 0) {
- termB[0] = 0;
- return 1;
- }
- /* Get result sign. */
- int result_sign = signA * signB;
- /* Allocate memory for multiplicand and multiplier. */
- int *multiplicand, *multiplier;
- multiplicand = (int *) ec_malloc((lenA + lenB + 1) * sizeof(int));
- multiplier = (int *) ec_malloc(MAX(lenA, lenB) * sizeof(int));
- unsigned int lenM, lenm;
- /* Copy the "shorter" number into multiplier (for less shifts of the multiplicand). */
- if (lenA > lenB || lenA == lenB) {
- lenM = arrncpy(multiplicand, termA, lenA, termA_1st_digit, (lenA - 1) - termA_1st_digit);
- lenm = arrncpy(multiplier, termB, lenB, termB_1st_digit, (lenB - 1) - termB_1st_digit);
- }
- else if (lenB > lenA) {
- lenM = arrncpy(multiplicand, termB, lenB, termB_1st_digit, (lenB - 1) - termB_1st_digit);
- lenm = arrncpy(multiplier, termA, lenA, termA_1st_digit, (lenA - 1) - termA_1st_digit);
- }
- /* Make the result (termB) 0. */
- unsigned int result_len = lenA + lenB + 1;
- for (unsigned int i = 0; i < result_len; i++) {
- termB[i] = 0;
- }
- unsigned int jRes = result_len - 1;
- for (int i = lenm - 1, sum = 0, transport = 0; i >= 0; i--) {
- for (int j = lenM - 1; j >= 0 && jRes >= 0; j--, jRes--) {
- /* Multiply and do the sum. */
- sum = (multiplier[i] * multiplicand[j]) + termB[jRes] + transport;
- /* Get the rest. */
- termB[jRes] = (sum % base);
- /* Get the transport. */
- transport = (sum - termB[jRes]) / base;
- }
- if (transport) {
- termB[jRes] = transport;
- transport = 0;
- }
- jRes = result_len - 1;
- /* abc -> abc0 -> abc00 -> abc000 -> ...*/
- lenM = arrnshift<int>(multiplicand, lenM, lenM, 1);
- }
- /* Count the number of insegnificant zeors. */
- int offset = 0;
- while (offset < (int)result_len && !termB[offset]) {
- offset++;
- }
- /* Set sign. */
- if (result_sign == -1) {
- termB[0] = '-';
- termB_1st_digit = 1;
- offset--;
- }
- else {
- termB_1st_digit = 0;
- }
- /* Delete insegnificant zeros, if any. */
- lenB = arrnshift<int>(termB, result_len, termB_1st_digit, -offset);
- free(multiplicand);
- free(multiplier);
- return lenB;
- }
- /* "Delete" from the startingI, offset elements (including the startingI element). */
- template <class type>
- unsigned int arrnshrink(type arr[], unsigned int len, unsigned int startingI, int offset)
- {
- offset *= -1;
- if (offset >= (int)len) {
- return len;
- }
- /* Start at the startingIndex. */
- int begin = startingI;
- /* End at the last Index(len-1), minus the offset. */
- int end = len - 1 - offset;
- /* Left to right, a[i] = a[i + offset]. */
- for (
- int i = begin;
- i <= end;
- i++)
- {
- arr[i] = arr[i + offset];
- }
- return len - offset;
- }
- /* Shift by enlarging to the left or to the right(if startingI >= len). */
- template <class type>
- unsigned int arrnfill(type arr[], unsigned int len, unsigned int startingI, int offset, type fill)
- {
- //arr = (type *)ec_realloc(arr, len * sizeof(type) + offset);
- /* Shift after end of arr = fill len -> len + offset =
- * = left shift by enlarging the arr.
- */
- if (startingI >= len) {
- len = len + offset;
- for (unsigned int i = len - offset; i < len; i++) {
- arr[i] = fill;
- }
- return len;
- }
- /* Start at last Index(len-1), plus the offset. */
- int begin = len - 1 + offset;
- /* End at the startingIndex + offset. */
- int end = offset + startingI;
- /* Right to left, a[i] = a[i - offset] */
- for (
- int i = begin;
- i >= end;
- i--)
- {
- arr[i] = arr[i - offset];
- }
- /* Left to right, from startingIndex until (startingIndex + offset), fill. */
- for (int i = end - offset; i < end; i++) {
- arr[i] = fill;
- }
- return len + offset;
- }
- /* Shift array (fill = 0) for pozitive offset, shrink for negative offset. */
- template <class type>
- unsigned int arrnshift(type arr[], unsigned int len, unsigned int startingI, int offset)
- {
- if (!offset || !len) {
- return len;
- }
- /* Shift by enlarging to the left or to the right(if startingI >= len). */
- if (offset > 0) {
- return arrnfill<type>(arr, len, startingI, offset, (type)0);
- }
- /* Shrink */
- return arrnshrink<type>(arr, len, startingI, offset);
- }
- /* Compares two arrnumbers (their modoule!). */
- template <class type>
- int arrnumber_cmp(type termA[], type termB[], unsigned int lenA, unsigned int lenB)
- {
- unsigned int iA, jB;
- iA = jB = 0;
- if (find_sign(termA)) {
- iA++;
- }
- if (find_sign(termB)) {
- jB++;
- }
- if ((lenA - iA) - (lenB - jB)) {
- return (lenA - iA) - (lenB - jB);
- }
- for (; iA < lenA; iA++, jB++) {
- if (termA[iA] != termB[jB]) {
- return termA[iA] - termB[jB];
- }
- }
- return 0;
- }
- /* Copies int arrDest, offset elements from arrStr, begining with the startingI. */
- template <class type>
- unsigned int arrncpy(type arrDest[], type arrSrc[], unsigned int len, unsigned int startingI, int offset)
- {
- if (startingI >= len || len <= 0) {
- return 0;
- }
- unsigned int jDest = 0;
- int end, begin;
- if (offset > 0) {
- begin = startingI;
- end = startingI + offset;
- if (end > (int)len) {
- return 0;
- }
- }
- else {
- begin = startingI + offset;
- end = startingI;
- if (begin < 0) {
- return 0;
- }
- }
- for (int i = begin; i <= end ; i++, jDest++) {
- arrDest[jDest] = arrSrc[i];
- }
- return jDest;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement