What I need to do is read a file which contains equations. I need to take the derivative of each equation and then write those derivative equations in a different .txt file. I've read all the equations into an array of character arrays and now I don't know what to do once I've stored them into the array. I really don't need help writing the equations into another file; I know I can figure that out.
What I need help on is finding a way to taking the derivative of the functions. The type of equations that are going to be read are not that complicated; they're going to be polynomials that don't need the chain rule or quotient rule. There will be, however, sin x, cos x and tan x. Some sample equations that would be read are.
-2x^2+2x-3
-2x+sinx-3
-x+sin2x-tanx
The trig functions will not have parenthesis and the variable will always be "x".
I just need a push in the right direction, please.
What you're really asking for is a parser.
A parser is basically a set of rules to read those equations and change/read (parse) each of them.
I'd try to iterate over each line of the file, and differentiate it considering you have a specific character set (i.e ^ means power, x is the parameter, etc.);
For example, some pseudo code:
Open the file.
While there's lines to read:
Read a line -
Seperate it by the operands (+,-,/,*)
For each part:
Find the power of x,
Reduce it by one,
...(derivating rules) // no way around, you have to implement each function if you want this to work as others mentioned in the comments.
Reconnect the parts into a string,
Add it to a list.
Print each element of the list.
If you need help translating that into C, just ask for it; I'll happily help you.
What you need to do, by the looks of things, is separate the expression into individual terms so that you can find the derivative of each in turn.
You can define a term as the largest sequence of characters not containing term separators such as (in your examples) + and -.
Hence the terms for your examples are:
-2x^2+2x-3 => 2x^2 2x 3
-2x+sinx-3 => 2x sinx 3
-x+sin2x-tanx => x sin2x tanx
For each term, you then need to evaluate the form of the term. The form will dictate how you create the derivative.
For example, you can detect if it contains a trigonometric function of the form [n]sin[m]x where n and m are optional numbers. To simplify things, you could add in those terms if they're not there, such as sinx becoming 1sin1x (I'll call this the full-form of the term). Being able to assume all subterms are present will greatly ease the derivative calculation.
Let's say the term is sin4x. Expanding that will give you 1sin4x which you can then split into term-multiplier 1, function sin and x-multiplier 4. Then using standard derivative knowledge nsinmx => (n*m)cosmx, this would become 4cos(4x) and that term would be done.
If it doesn't contain a trigonometric function, you can use the same full-form trick to cover all of the power/constant expressions with the following rules in turn:
if it's a constant (all numeric), append x^0 (multiply by 1).
if it ends with x, append ^1, so 4x becomes 4x^1.
if it starts with x, prefix it with 1, so x^3 becomes 1x^3.
Once that's done, you will have a full-form of ax^b and you can then create the derivative (ab)x^(b-1) and post-process it:
if the bit after x is ^0, remove the whole x^0.
if the bit after x is ^1, remove the ^1.
if the bit before the x is 1, remove it.
if the bit before the x is 0, remove the entire term (and preceding term separator, if any).
So, taking a complex combination of your test data:
-2x^2 + 5x + 4sin3x - 3
which can be treated as:
0 - 2x^2 + 5x + 4sin3x - 3
The following actions happen to each term:
0 [0x^1] (derives as) 0, remove it.
2x^2 [2x^2] (derives as) (2*2)x^(2-1) => 4x^1 => 4x
5x [5x^1] (derives as) (5x1)x^(1-1) => 5x^0 => 5
4sin3x [4sin3x] (derives as) 12cos3x
3 [3x^0] (derives as) 0, remove it and preceding '-'
Thus you end up with - 4x + 5 + 12cos3x which, although my calculus education is some thirty years in the past (and I don't think I've used it since, though I will no doubt be using it next year when my eldest hits secondary school), Wolfram Alpha appears to agree with me :-)
This function will parse the text, cut it in to different parts identified by type[i], stores in a structure. It recognizes x, +, -, and numbers. It can be expand it to include other operators etc.
#define maxlen 50
#define idx 0 //X variable
#define idnumber 1 //number
#define idplus 2 //+ sign
#define idminus 3 //- sign
struct foo
{
int type[10];//each type can be a number (idnum), +, -, etc.
int num[10];//if type[i] is number then num[i] identifies that number
int count;//total number of parts
};
void parse_one_line(struct foo *v, const char *s)
{
char buf[maxlen];
memset(buf, 0, maxlen);
int j = 0;
//remove white spaces
for (int i = 0, len = strlen(s); i < len; i++)
{
if (s[i] == ' ') continue;
buf[j] = s[i];
j++;
}
char part[maxlen];
v->count = 0;
for (int i = 0, len = strlen(buf); i < len; i++)
{
char c = buf[i];
if (c == 'x')
{
v->type[v->count] = idx;
v->count++;
}
else if (c == '+')
{
v->type[v->count] = idplus;
v->count++;
}
else if (c == '-')
{
v->type[v->count] = idminus;
v->count++;
}
else if (c >= '0' && c <= '9')
{
int j = 0;
memset(part, 0, maxlen);
for (; i < len; i++)
{
c = buf[i];
if (c >= '0' && c <= '9')
{
part[j] = c;
j++;
}
else
{
break;
}
}
i--;
v->num[v->count] = atoi(part);
v->type[v->count] = idnumber;
v->count++;
}
}
for (int i = 0; i < v->count; i++)
{
switch (v->type[i])
{
case idnumber: printf("%d", v->num[i]); break;
case idx: printf("X"); break;
case idplus: printf("+"); break;
case idminus: printf("-"); break;
default:break;
}
}
printf("\n");
}
int main()
{
struct foo st;
parse_one_line(&st, "-23x + 2 + 2x - 3");
return 0;
}
Related
I have an assignment that basically is asking to justify a paragraph given line length. So for instance the paragraph
"I am a student of C, this is my first assignment. I hope I finish on time." given line length of 17 should be as follows:
output
I am a student of
C, this is my
first assignment.
I hope I finish
on time.
I am having trouble with dynamically placing spacing in between the words. I currently have a function that counts the words in a paragraph and stores them into a 2d array but I have no idea how to a) calculate the amount of spacing in between words and b) how to dynamically print that justified paragraph.
Here is the code I have so far:
int getAllWordsFrom2DArray(char *paragraph, char words[MAX_NUMBER_OF_WORDS][MAX_WORD_LENGTH]) {
int i,j,totalWords = 0;
for(i=0; i < strlen(paragraph); i++) {
int wordLength;
if (paragraph[i] == ' ' || paragraph[i+1] == '\0') {
totalWords++;
wordLength = i;
for(j=0; j < wordLength; j++) {
words[i][j] = paragraph[j];
}
}
}
printf("%s", words);
return totalWords;
}
//Code in progress
int getNumberOfWordsForNextLine(int totalWords, int lineLength, char words[MAX_NUMBER_OF_WORDS][MAX_WORD_LENGTH]) {
int wordsForNextLine = 0;
for(int i=0; i < totalWords; i++) {
wordsForNextLine = 0 ;
}
}
//code in progress
void printNextLine(int wordsForNextLine) {
}
//skeleton code provided by instructor
void justifyAndPrintParagraph(char* paragraph, int lineLength) {
char words[MAX_NUMBER_OF_WORDS][MAX_WORD_LENGTH];
int totalWords = getAllWordsFrom2DArray(paragraph, words);
int processedWords = 0;
while (processedWords < totalWords) {
int wordsForNextLine = getNumberOfWordsForNextLine(totalWords, lineLength, words);
printNextLine(wordsForNextLine);
processedWords += wordsForNextLine;
}
}
To clarify, we are not allowed to use strlok. Essentially we are expected to just use the basics in doing this. I need to use the void justifyAndPrintParagraph function and signature but other than that I'm free to do whatever.
Edit: I forgot to add that if spaces cannot be evenly divided then the extra spaces are to be allocated left to right.
Any help is greatly appreciated.
Consider how many spaces you have to distribute. For example, given the input:
18
I am the very model of a modern Major-General.
Computing the number of words that fit on the line goes:
"I" + "am" + "the" + "very" + (4-1 words) --> 13
"I" + "am" + "the" + "very" + "model" + (5-1 words) --> 19
So only the first 4 words fit on an 18-character line. The number of space characters to distribute are then easily calculated:
N = max_line_width - sum_of_word_lengths
Now for the hard part: how many spaces between each word? Your homework expects you to divvy extra unbalanced spaces left-to-right, meaning that each pair of words may have a different number of space characters.
However, the difference will always be a single space character. Take a moment to convince yourself this is true:
I···am···the··very
-2-4-6-8-0-2-4-6-8
In our little example, we find that there are three space characters in the first two inter-word spacings, and two space characters in the last.
The minimum number of space characters per inter-word spacing is easy enough to caluclate:
nsp = N / (number_of_words_in_line - 1)
Beware! What happens if you have only one word on the line? (Do you really need to distribute spaces for such a line?)
And now, for the cool tricky math part, you can calculate the number of times you need to add a space to the inter-word spacing as:
nplus1 = N - nsp * (number_of_words_in_line - 1)
or just:
nplus1 = N % (number_of_words_in_line - 1)
Keep in mind that it is possible that all inter-word spacings are the same number of space characters, and may be exactly one space character even. Notice how our calculations work just as well in those cases.
Now you can print the words for the line in a loop, adding nsp space characters after every word, plus an extra space after the first nplus1 words.
Remember, the last word of the line doesn’t get any spaces. It is followed by a newline!
Hopefully this should help you work your way through this assignment.
(I personally think it is a bit of a careless assignment as your first ever, introduction to C class.)
And now, if I have made errors, it is because I am very, very sleepy. Someone will surely point it out if I have.
So using Dúthomhas' suggestion I was able to create the function below:
void justifyAndPrintLine(char words[MAX_NUMBER_OF_WORDS][MAX_WORD_LENGTH], int processedWords, int amountOfWordsForNextLine, int lineLength) {
int total = 0;
for (int i = processedWords; i < processedWords + amountOfWordsForNextLine; i++) {
total += (int) strlen(words[i]);
}
int spaces = lineLength - total;
int spacesBetweenWords = spaces / (amountOfWordsForNextLine - 1);
int spacesRemaining = spaces % (amountOfWordsForNextLine - 1);
int spaceForThisWord;
int leftWords = processedWords + amountOfWordsForNextLine;
while (processedWords != leftWords) {
spaceForThisWord = spacesBetweenWords;
if (spacesRemaining > 0) {
spaceForThisWord++;
spacesRemaining--;
}
printLine(words[processedWords], spaceForThisWord);
processedWords++;
}
}
A key part of my understanding of the math was that the difference in spacing was always going to a single space character. Borrowing his math I was able to properly justify the paragraph. Thanks again Dúthomhas!
My problem is that i dont know what this functions do, thats program
from my teacher(not whole program just functions). Just wanna ask you what this functions do, mainly why
i store my number from right to left at string? thanks
#include<stdio.h>
#include<string.h>
#define MAX 1000
void str_to_num(char *str, char *number, int *dlzka)
{
int i;
for(i=0; i < MAX; i++)
number[i] = 0;
*dlzka = strlen(str);
for(i = 0; i < *dlzka; i++)
cis[(*dlzka) - 1 - i] = str[i] - '0';
}
void plus(char *cislo, int *d1, char *cis2, int d2)
{
int i; prenos = 0;
if(*d1 < d2)
*d1 = d2;
for(i = 0; i < *d1; i++)
{
pom = number[i] + number[i];
pom += prenos;
number[i] = pom % 10;
prenos = pom / 10;
}
}
Here is the lesson your teacher should be teaching:
There is a difference between the numerical value of 1, and the computer code (ASCII for example) that is used to represent character 1 displayed on the screen or typed on the keyboard.
Every time you see 1 on the screen, your computer sees 49 in memory.
0 is 48, 2 is 50 and so on.
Conveniently, all digit characters are arranged in a sequence from 0 to 9, so to convert their character codes to their numeric values all you have to do is subtract the character code of zero to get the digit position in the sequence.
For example: 49 - 48 = 1 --> '1' - '0' = 1
And this is how the first function, str_to_num works.
C language does not provide a variable large enough to work with 100 digit numbers, so you need to sum them up one digit at a time.
The second function has completely wrong variable names, but it is still pretty obvious what it is trying to do:
It sums up two single digit numbers, then stores the ones part of the result in an array and the tenth (if sum is > 9) in a helper variable.
As already suggested in the comments, this is how you sum up numbers manually on a page one digit at a time.
I don't know what prenos means in your language, but in English this variable should be called carry and it keeps the overflowing tens digit for the next round.
There is however something missing from the sum function: if the sum of the last (leftmost) two digits is more than 9, the extra 1 will be lost, and the result will be wrong.
Check the original code your teacher gave you - either you copied it wrong, or he is giving a bad example.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
So i recently did a university exam and one of the questions asked us to create a program that would print out the nth number in the tribonacci sequence (1,1,1,3,5,9,17,31...). These numbers were said to go as large as 1500 digits long. I created a recursive function that worked for the first 37 tribonacci numbers. But a stack overflow occurred at the 38th number. The question had warned us about this and said that we would somehow need to overcome this, but i have no idea how. Were we meant to create our own data type?
double tribonacci(int n){
if(n < 4){
return 1;
}else{
return tribonacci(n-3) + tribonacci(n-2) + tribonacci(n-1);
}
}
int main(int argc, char *argv[]){
double value = tribonacci(atoi(argv[1]));
printf("%lf\n", value);
}
This is the solution i wrote under exam conditions, which was within 15 minutes.
The program took the value of n from an input in the command line. We were not allowed to use any libraries except for stdlib.h and stdio.h. So with all that said, how might one create a data type large enough to print out numbers with 1500 digits (since the double data type only holds enough for up until the 37th tribonacci number)? Or is there another method to this question?
You should use some arbitrary-precision arithmetic library (a.k.a. Bigints or bignums) if your teacher allows them. I recommend GMPlib, but there are others.
See also this answer (notably if your teacher wants you to write some crude arbitrary precision addition).
For a development time limited exam solution, I'd definitely go for the quick & dirty approach, but I wouldn't exactly complete it within 15 minutes.
The problem size is restricted to 1500 characters, computing tribonacci indicates that you will always need to carry subresult N-3, N-2 and N-1 in order to compute subresult N. So lets define a suitable static data structure with the right starting values (its 1;1;1 in your question, but I think it should be 0;1;1):
char characterLines[4][1501] = { { '0', 0 }, { '1', 0 }, { '1', 0 } };
Then define an add function that operates on character arrays, expecting '\0' as end of array and the character numbers '0' to '9' as digits in a way that the least significant digit comes first.
void addBigIntegerCharacters(const char* i1, const char* i2, char* outArray)
{
int carry = 0;
while(*i1 && *i2)
{
int partResult = carry + (*i1 - '0') + (*i2 - '0');
carry = partResult / 10;
*outArray = (partResult % 10) + '0';
++i1; ++i2; ++outArray;
}
while(*i1)
{
int partResult = carry + (*i1 - '0');
carry = partResult / 10;
*outArray = (partResult % 10) + '0';
++i1; ++outArray;
}
while(*i2)
{
int partResult = carry + (*i2 - '0');
carry = partResult / 10;
*outArray = (partResult % 10) + '0';
++i2; ++outArray;
}
if (carry > 0)
{
*outArray = carry + '0';
++outArray;
}
*outArray = 0;
}
Compute the tribonacci with the necessary number of additions:
// n as 1-based tribonacci index.
char* computeTribonacci(int n)
{
// initialize at index - 1 since it will be updated before first computation
int srcIndex1 = -1;
int srcIndex2 = 0;
int srcIndex3 = 1;
int targetIndex = 2;
if (n < 4)
{
return characterLines[n - 1];
}
n -= 3;
while (n > 0)
{
// update source and target indices
srcIndex1 = (srcIndex1 + 1) % 4;
srcIndex2 = (srcIndex2 + 1) % 4;
srcIndex3 = (srcIndex3 + 1) % 4;
targetIndex = (targetIndex + 1) % 4;
addBigIntegerCharacters(characterLines[srcIndex1], characterLines[srcIndex2], characterLines[targetIndex]);
addBigIntegerCharacters(characterLines[targetIndex], characterLines[srcIndex3], characterLines[targetIndex]);
--n;
}
return characterLines[targetIndex];
}
And remember that your least significant digit comes first when printing the result
void printReverse(const char* start)
{
const char* printIterator = start;
while (*printIterator)
{
++printIterator;
}
do
{
putchar(*(--printIterator));
} while (printIterator != start);
}
int main()
{
char* c = computeTribonacci(50); // the real result is the array right-to-left
printReverse(c);
}
As said, this is kindof quick & dirty coded, but still not within 15 minutes.
The reason why I use a separate char per decimal digit is mainly readability and conformity to the way how decimal math works on pen&paper, which is an important factor when development time is limited. With focus on runtime constraints rather than development time, I'd probably group the numbers in an array of unsigned long long, each representing 18 decimal digits. I would still focus on decimal digit groupings, because this is a lot easier to print as characters using the standard library functions. 18 because I need one digit for math overflow and 19 is the limit of fully available decimal digits for unsigned long long. This would result in a few more changes... 0 couldn't be used as termination character anymore, so it would probably be worth saving the valid length of each array. The principle of add and computeTribonacci would stay the same with some minor technical changes, printing would need some tweaks to ensure a length 18 output for each group of numbers other than the most significant one.
You require a different algorithm. The code posted cannot suffer from an integer overflow, as it does all its calculations in doubles. So you are probably getting a stack overflow instead. The posted code uses exponential time and space, and at N=38 that exponential space is probably overflowing the stack. Some alternatives, in increasing order of efficiency and complexity:
Use the "memoization" technique to optimize the algorithm you have.
Build up the answer starting by calculating N=4, and iterating upwards. No recursion is then needed.
Do the mathematics (or find someone who can) to get the "closed form solution" that allows direct calculation of the answer. See https://en.wikipedia.org/wiki/Fibonacci_number#Closed-form_expression for how this works for regular fibonacci numbers.
You will also need a "big number" data structure - see other answers.
You need to replace the + operation with an operator ADD made by yourself and encode BigIntegers as you wish -- there are lots of ways to encode BigIntegers.
So you need to define yourself a datatype BigInteger and the following operations
ADD : BigInteger, BigInteger -> BigInteger
1+ : BigInteger -> BigInteger
2- : BigInteger -> BigInteger
<4 : BigInteger -> boolean
The constants 1,2,4 as BigInteger
and after having replaced these things write a standard function to compute fibb in linear time and space.
The idea of subsequences is explained very well in this post:Generate subsequences
But i didnt understand the answers on that question because im a beginner.
What i wanted to know is if i could make my C program any more efficient while still keeping it simple and understandable and without using functions?
#include <stdio.h>
#define NUM 123456
int main(void) {
int i,num=NUM,x,y,mask,digits=0,max=1;
while ( num != 0 ) { //calculate digits
num /= 10;
digits++;
}
for ( i = 1; i <= digits; i++ ) { //calculate max number of subsequences
max *= 2;
}
max=max-2;
printf("Subsequences are:\n");
for ( i = 1; i <= max ; i++ ) {
mask = i; //digit selector
x = 1; //multiplier
num = NUM;
y=0; //subsequence value
while ( num != 0 ) {
if ( mask % 2 == 1 ) {
y += num % 10 * x;
x *= 10;
}
num /= 10;
mask /= 2;
}
printf("%d \n" , y);
}
return 0;
}
Note that when we define NUM as a number such as 5111 or 100 some of the subsequences appear twice. Is there any simple way to fix that?
Thanks!
The root of the reason that certain subsequences appear more than once with some numbers is because those numbers have repetitions of the same digit.
That repetition could be eliminated by saving each subsequence in an array and checking that array to see if the specific subsequence is already in the array. If already in the array, do not print. Otherwise, add subsequence to array contents and print
The problem can be divided into two tasks: (1) find all subsequences of an array of digits and (2) pack and unpack integers into digits.
Let's consider the subsequences of the array {a, b, c}. You can generate them by walking through the array from left to right and follow two paths: One where you include the current element in a subsequence and one where you don't.
That leads to a recursive approach tat we can represent as a tree:
{}
/ \
{} {a}
/ \ / \
{} {b} {a} {ab}
/ \ / \ / \ / \
{} {c} {b} {bc} {a} {ac} {ab} {abc}
When we branch left, we skip the current element and when we go right, we include the element. The elements themselves are the depth of the tree: On the first level we treat element a, on the next band on the last c.
The bottom row has all subsequences. This includes the empty sequence and the full sequence, which you don't want. But let's include them for now. (The arrays in the bottom row are usually called a power set, which is a nice web-searchable term.)
I mentioned recursion, which entails recursive functions, and functions are out.
So we need to tackle the problem another way. Let's turn the tree on its side. A dash denotes that the element was skipped. The notation on the right uses another notation: 0 means the element was skipped, 1 means the element was included:
- - - 000
- - c 001
- b - 010
- b c 011
a - - 100
a - c 101
a b - 110
a b c 111
I hope the codes on the right look familiar, because that's how you count from 000 to 111 in binary. That's a nice way to enumerate our elements. Now we need a way to tell which bits are set in each number.
The rightmost bit is set when the number is odd. We can find out about the other bits by repeatedly dividing the number by two, which in binary is a shift to the right, discarding the rightmost bit.
Now how to extract the digits from the original number? That number is a decimal number; it's in base 10. We can use the same approach as for finding the bits in the binary number, because the bits 0 and 1 are the binary digits.
Start with the number. The last digit is the result of taking the remainder after a division by 10. Then divide the number by ten until it is zero. This code yields the digits from right to left. So does the code for finding the bits, which means we can find whether a bit is set and which digit to print in a single loop, always taking the rightmost bit and if it is set, print the rightmost digit of the original number.
The empty and the full subsequences are the first and last items in the enumeration. If you don't want them, skip them.
That leaves the problem of the duplicated subsequences if the digit has repeated digits. I don' see an easy way to solve this except user3629249's suggestion to create the subsequence anyway and later check whether is has already been printed.
An easy way to do this is to keep an array of the subsequences. That array has max entries. After you have filled that array, sort it and then print it, but skip entries that are equal to the previous entry.
Here's an example implementation that uses an array of digits so that the original number doesn't have to be decomposed each time. It uses the sorting function qsort from <stdlib.h>, which requires a sorting function:
#include <stdlib.h>
#include <stdio.h>
#define NUM 412131
typedef unsigned int uint;
int uintcmp(const void *pa, const void *pb)
{
const uint *a = pa;
const uint *b = pb;
return (*a > *b) - (*a < *b);
}
int main(void)
{
uint digit[20]; // array of digits
size_t ndigit = 0; // length of array
uint num = NUM;
uint max = 1;
size_t i;
while (num) {
digit[ndigit++] = num % 10;
num /= 10;
max *= 2;
}
uint res[max]; // array of subsequences
for (i = 0; i < max; i++) {
uint mask = i; // mask for bit detection
uint j = ndigit; // index into digit array
uint s = 0;
while (j--) {
if (mask % 2) s = s*10 + digit[j];
mask /= 2;
}
res[i] = s;
}
qsort(res, max, sizeof(*res), uintcmp);
for (i = 1; i < max - 1; i++) {
if (res[i] != res[i - 1]) printf("%u\n", res[i]);
}
return 0;
}
I have the following problem:
The point (a) was easy, here is my solution:
#include <stdio.h>
#include <string.h>
#define MAX_DIGITS 1000000
char conjugateDigit(char digit)
{
if(digit == '1')
return '2';
else
return '1';
}
void conjugateChunk(char* chunk, char* result, int size)
{
int i = 0;
for(; i < size; ++i)
{
result[i] = conjugateDigit(chunk[i]);
}
result[i] = '\0';
}
void displaySequence(int n)
{
// +1 for '\0'
char result[MAX_DIGITS + 1];
// In this variable I store temporally the conjugates at each iteration.
// Since every component of the sequence is 1/4 the size of the sequence
// the length of `tmp` will be MAX_DIGITS / 4 + the string terminator.
char tmp[(MAX_DIGITS / 4) + 1];
// There I assing the basic value to the sequence
strcpy(result, "1221");
// The initial value of k will be 4, since the base sequence has ethe length
// 4. We can see that at each step the size of the sequence 4 times bigger
// than the previous one.
for(int k = 4; k < n; k *= 4)
{
// We conjugate the first part of the sequence.
conjugateChunk(result, tmp, k);
// We will concatenate the conjugate 2 time to the original sequence
strcat(result, tmp);
strcat(result, tmp);
// Now we conjugate the conjugate in order to get the first part.
conjugateChunk(tmp, tmp, k);
strcat(result, tmp);
}
for(int i = 0; i < n; ++i)
{
printf("%c", result[i]);
}
printf("\n");
}
int main()
{
int n;
printf("Insert n: ");
scanf("%d", &n);
printf("The result is: ");
displaySequence(n);
return 0;
}
But for the point b I have to generate the n-th digit in logarithmic time. I have no idea how to do it. I have tried to find a mathematical property of that sequence, but I failed. Can you help me please? It is not the solution itself that really matters, but how do you tackle this kind of problems in a short amount of time.
This problem was given last year (in 2014) at the admission exam at the Faculty of Mathematics and Computer Science at the University of Bucharest.
Suppose you define d_ij as the value of the ith digit in s_j.
Note that for a fixed i, d_ij is defined only for large enough values of j (at first, s_j is not large enough).
Now you should be able to prove to yourself the two following things:
once d_ij is defined for some j, it will never change as j increases (hint: induction).
For a fixed i, d_ij is defined for j logarithmic in i (hint: how does the length of s_j increase as a function of j?).
Combining this with the first item, which you solved, should give you the result along with the complexity proof.
There is a simple programming solution, the key is to use recursion.
Firstly determine the minimal k that the length of s_k is more than n, so that n-th digit exists in s_k. According to a definition, s_k can be split into 4 equal-length parts. You can easily determine into which part the n-th symbol falls, and what is the number of this n-th symbol within that part --- say that n-th symbol in the whole string is n'-th within this part. This part is either s_{k-1}, either inv(s_{k-1}). In any case you recursively determine what is n'-th symbol within that s_{k-1}, and then, if needed, invert it.
The digits up to 4^k are used to determine the digts up to 4^(k+1). This suggests writing n in base 4.
Consider the binary expansion of n where we pair digits together, or equivalently the base 4 expansion where we write 0=(00), 1=(01), 2=(10), and 3=(11).
Let f(n) = +1 if the nth digit is 1, and -1 if the nth digit is 2, where the sequence starts at index 0 so f(0)=1, f(1)=-1, f(2)-1, f(3)=1. This index is one lower than the index starting from 1 used to compute the examples in the question. The 0-based nth digit is (3-f(n))/2. If you start the indices at 1, the nth digit is (3-f(n-1))/2.
f((00)n) = f(n).
f((01)n) = -f(n).
f((10)n) = -f(n).
f((11)n) = f(n).
You can use these to compute f recursively, but since it is a back-recursion you might as well compute f iteratively. f(n) is (-1)^(binary weight of n) = (-1)^(sum of the binary digits of n).
See the Thue-Morse sequence.