C: Reading Complex Numbers
A complex number is a number that can be expressed in the form
a + bi
, wherea
andb
are real numbers andi
is the imaginary unit, satisfying the equationi*i=−1
. In this expression,a
is the real part andb
is the imaginary part of the complex number.From wikipedia
The following code, will open a file where each line contains one complex number, read the number and store it into the appropriate variables.
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { const char *filename = argv[1]; FILE *fin = fopen(filename, "r"); // Making sure we managed to open the file if (fin != NULL) { //Initially this pointer will hold the whole line, eventually the data for the second Component will be removed char *first_value = NULL; size_t length_of_buffer = 0; ssize_t bytes_read; // Read Line by line until end of file: // If *line is set to NULL and *length_of_buffer is set 0 before the call, then getline() will allocate a buffer for storing the line. // This buffer should be freed by the user program even if getline() failed. while ((bytes_read = getline(&first_value, &length_of_buffer, fin)) != -1) { printf("Data = '%s' : Length = %zu\n", first_value, bytes_read); // Create char string to store the second Component char *second_value; // We are a bit wasteful here but it makes the code simpler second_value = (char *) malloc(bytes_read * sizeof(char)); // Create Imaginary flag to distinguish real values from imaginary values - One for each Component char imaginary_flag[2] = {0, 0}; // Initialize Iterators // i: for pointing to characters of current line // j: for pointing to characters in first Component // k: for pointing to characters in second Component int i, j = 0, k = 0; // Flag to indicate that first character if the first Component was found - This helps distinguish between first and second Component char met_a_number = 0; // Flag to indicate first Component ends and we should process the second Component char copy_to_second_value = 0; // To store the previous character value, we use it to check that when a sign is found, it does not belong to an exponential char previous_character = '\0'; for (i = 0; i < bytes_read; i++) { // Initialize current character being processed/evaluated from the line const char current_character = first_value[i]; // Find the 'j' character that shows that this number is imaginary, then drop the character if (current_character == 'j') { if (copy_to_second_value == 0) { // First Component is the imaginary part imaginary_flag[0] = 1; } else { // Second Component is the imaginary part imaginary_flag[1] = 1; } continue; } //We check that the current character is useful to us if (!(current_character == ' ' || current_character == '(' || current_character == ')')) { // If current character still part of first Component [based on flag] if (copy_to_second_value == 0) { // Check when second Component begins // When we find one of the sign characters and it is not part of an exponential, then we switch to the second Component // Exclude if previous character was "e" because after "e" a sign is followed if (current_character == '-' || current_character == '+') { if (met_a_number == 1 && previous_character != 'e') { // Update Flag to indicate that second Component/Value begins copy_to_second_value = 1; // Terminate first Component/Value of current Line first_value[i] = '\0'; second_value[k++] = current_character; } else { // Update First Component with the current character value first_value[j++] = current_character; } } // If current character still part of the first Component else { // Update First Component with the current character value first_value[j++] = current_character; // A valid character of a number was found, so we are processing a number. // If this is the first time it happens, we are processing the first Component met_a_number = 1; } } // If current character part of second Component [based on flag] else { second_value[k++] = current_character; } } // If current character belongs in one of the garbage characters else { // If current character is garbage number and we already met a number // then we start copying to the second Component if (met_a_number == 1) { copy_to_second_value = 1; first_value[i] = '\0'; } } // Store current_character before reading the next previous_character = current_character; } // Properly terminate first Component if (first_value[j - 1] == '\n') { first_value[j - 1] = '\0'; } else { first_value[j] = '\0'; } // Properly terminate second Component second_value[k - 1] = '\0'; // To store the first and second Components in float format double numbers[2]; // Convert to float and Print first Component sscanf(first_value, "%lf", &(numbers[0])); printf("%.f = '%s' is imaginary = %s\n", numbers[0], first_value, imaginary_flag[0] == 0 ? "FALSE" : "TRUE"); // Convert to float and Print second Component if it exists if (copy_to_second_value == 1) { sscanf(second_value, "%lf", &(numbers[1])); printf("%.f = '%s' is imaginary = %s\n", numbers[1], second_value, imaginary_flag[1] == 0 ? "FALSE" : "TRUE"); } free(second_value); double real = 0, imaginary = 0; if (copy_to_second_value == 1) { if (imaginary_flag[0] == imaginary_flag[1]) { fprintf(stderr, "Invalid input line.\n"); if (imaginary_flag[0] == 0) { fprintf(stderr, "None of the components is imaginary\n"); } else { fprintf(stderr, "Both components are imaginary.\n"); } continue; } if (imaginary_flag[0] == 0) { real = numbers[0]; imaginary = numbers[1]; } else { real = numbers[1]; imaginary = numbers[0]; } } else { if (imaginary_flag[0] == 0) { real = numbers[0]; } else { imaginary = numbers[0]; } } printf("Real part: '%f'\tImaginary part: '%f'\n", real, imaginary); printf("\n"); } free(first_value); fclose(fin); } else { fprintf(stderr, "Failed to open file '%s'\n", filename); return EXIT_FAILURE; } return EXIT_SUCCESS; }
This application will only perform some basic checks on the input, a lot of invalid data can pass as valid..
What this application expects though is the following:
- On each line, there can be either one or two numbers.
- The numbers can be encapsulated in parenthesis ()
- The first number can have a sign or not
- There might be space between the characters or not
- There might be space between the sign characters and the numbers
- The imaginary part of the number will have the character
j
either before the number or after, attached to the number