Help with console input

Pages: 12
Hi guys:

I'm coding this small program to calculate roots in a function using bisection method.

I'm using this code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <cmath>
#include <stdlib.h>
using namespace std;
double f(double x);
double biseccion(double a, double b, double tolerancia, int maxiter);
int main()
{
    double a, b, raiz, h;
    double tolerancia=0.00000;
    int maxiter=25;
    cout << "Input interval start: ";
    cin >> a;
    cout << "Input interval end: ";
    cin >> b;
    cout << "\n";
    h=f(a)*f(b);
    if (h==0)
    {
        cout << "La raiz es cero.";
        return 0;
    }
    if (h>0)
    {
        do
        {
            cout << "There is no root in that interval.";
            cout << "\n";
            cout << "\n";
            cout << "Input interval start: ";
            cin >> a;
            cout << "Input interval end: ";
            cin >> b;
            cout << "\n";
            h=f(a)*f(b);
        }
        while (h>0);
        if (h==0)
        {
            cout << "Root is zero.";
            return 0;
        }        
    }
    if (h<0)
    {
    
    cout << "  # "<<"\n"<<"Iteration"<<"\t"<<"   A"<<"\t"<<"   B"<<"\t"<<"   C"<<"\t"<<"   f(c)"<<endl;
    raiz=biseccion(a,b,tolerancia,maxiter);
    cout << "\n";
    cout << "The root is: "<< raiz <<endl;
    }
    return 0;
}
 
 double f(double x)
 {
        return x*x*x-x-2;
 }
 double biseccion(double a, double b, double tolerancia, int maxiter)
 {
        double c;
        int numiter=1;
        do
        {
            c=(a+b)/2;
            if(f(a)*f(c)<0)
            {
               b=c;
            }
            else
            {
                a=c;
            }
/*
            if(f(b)*f(c)<0)
            {
               a=c;
            }
            else
            {
                b=c;
            }
*/            
            cout<<"     "<<numiter<<"\t"<<"\t"<<a<<"\t"<<b<<"\t"<<c<<"\t"<<f(c)<<endl;
            numiter++;
         }
         while((abs(f(c))>tolerancia)&&(numiter<maxiter));
         return c;
}


I want to focus on this for a moment.

1
2
3
4
 double f(double x)
 {
        return x*x*x-x-2;
 }


That function has x*x*x-x-2 before return, thats the mathematical function I need to calculate. Now, what I want is that instead I code this function user could input it by console. Something like "Input function: ", so user input something like "x*x-x+5", and THAT is placed after the return.

First I thought about using a string to store the user input, but of course, I can't use a string in a function that uses a double variable.

So, I thought, maybe I could convert from a string to a double variable. I read this article (http://www.cplusplus.com/articles/D9j2Nwbp/), but all I got is zero.

Sooo, my question is:

Is there a way to achieve what I need?, convert the content of a string variable (x*x-x+5) to used in a double variable?, replace the x*x*x-x-2 after the return with whatever user input when asked?

Thanks in advance.
You need to manually parse the expression yourself, basically doing what your compiler would do. If you limit it to simple expressions, your task is a bit easier, but if you allow more complex syntax your task becomes harder.

Can you give an example of the syntactically most complex expression you will allow in your program? Like, pulling out all the stops?
Thanks for answer.

Well, I was adviced about using a parser library, like muparser (http://muparser.beltoforion.de/index.html), but I never could make it work properly. Besides, I'm not sure if a parser is what I really need?. You think that's what I need?
Like I said, it depends on the complexity of expressions you want to deal with. Can you show me the most complex expression you want to allow as input?
Well, they are mostly simple expressions:

(x-1)(x-2)
x^3-x-3
x^2-3x+2

Things like that. Maybe the most complex would be something like 7x^5-4x^4+6x^3-3x^2-x+9=0
Actually, your most complex example is the one with the parenthesis. Do you plan to support nesting?
If nesting means a function inside a function, no, I will only use the code I show earlier.
So, you will write:
(x+1)(x-1)
But you will not write:
(x(x+1))(x-(1-(7x)))
Is this correct?
Oooh, that nesting...

Well, there is a small chance that I will use one or two functions like that, mostly because when you write something like x^3-3x^2+2x-5 c++ need to see it like (x*x*x)-(3(x*x))+(2*x)-5...
OK then, I'd recommend a recursive parser. Basically, you pretend the entire expression is wrapped in parens (), and whenever you encounter an open paren, recurively call the parse function on the rest of the expression, and go back up the recursion stack when you encounter a close paren ).

I would recommend a library if you can get one set up and if you are allowed to use one, bur if not, you will have to write the parser yourself.
Ok, I try muparser (http://muparser.beltoforion.de/index.html) and after download it I include the libraries used by muparser.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <muParser.h>
#include <muParserBase.h>
#include <muParserBytecode.h>
#include <muParserCallback.h>
#include <muParserDef.h>
#include <muParserError.h>
#include <muParserFixes.h>
#include <muParserStack.h>
#include <muParserToken.h>
#include <muParserTokenReader.h>
using namespace mu;
using namespace std;
double f(double x);
double biseccion(double a, double b, double tolerancia, int maxiter);
string funcion;
mu::Parser parser;
int main()
{
    try
    {
    double a, b, raiz;
    double tolerancia=0.00000;
    int maxiter=25;
    double fVal=0;
    
    parser.DefineVar("funcion", &fVal);
    cout << "Input function: ";
    cin >> funcion;
    cout << "Input interval start: ";
    cin >> a;
    cout << "Input interval end: ";
    cin >> b;
    cout << "\n";
        
    parser.SetExpr(funcion);
    fVal = parser.Eval();

    cout << "  # "<<"\n"<<"Iteracion"<<"\t"<<"   A"<<"\t"<<"   B"<<"\t"<<"   C"<<"\t"<<"   f(c)"<<endl;
    raiz=biseccion(a,b,tolerancia,maxiter);
    cout << "\n";
    cout << "The root is: "<< raiz <<endl;
    return 0;
    }  
        catch (Parser::exception_type &e)
    {
     std::cout << e.GetMsg() << endl;
    }
    
}
 
 double f(double x)
 {
        return x*x*x-x-2;
 }
 

 
 double biseccion(double a, double b, double tolerancia, int maxiter)
 {
        double c;
        int numiter=1;
        do
        {
            c=(a+b)/2;
            if(f(a)*f(c)<0)
            {
               b=c;
            }
            else
            {
               a=c;
            }
            cout<<"     "<<numiter<<"\t"<<"\t"<<a<<"\t"<<b<<"\t"<<c<<"\t"<<f(c)<<endl;
            numiter++;
         }
         while((abs(f(c))>tolerancia)&&(numiter<maxiter));
         return c;
}


I try that code and I can't resolve the error "Unexpected token "x" found at position 0". And when I replace "x*x*x-x-2" for "funcion" then the compiler nag me about conversion between string and double. It's like muparser it's not parsing... I'm so frustrated...
Last edited on
Can you copy and paste the exact error messages you're getting?
"Unexpected token "x" found at position 0"

And if I replace "x*x*x-x-2" for "funcion", then I got this error: "cannot convert ‘std::string’ to ‘double’ in return".

If I read the documentation of muparser correctly, I need to define a variable that will contain what I need to parse (in this case the variable "funcion"), so I declare it with:

parser.DefineVar("funcion", &fVal);

Where &fVal is tha name for c++ and "funcion" is the name for muparser.

So, I

1
2
    cout << "Input function: ";
    cin >> funcion;


In theory, muparser will take the content from "funcion", parse it, and store result of parsing in fVal. Before muparser could parse, it need to know where is the expression to be parsed, so I

 
    parser.SetExpr(funcion);


And then

fVal = parser.Eval();

But if I use fVal instead of "x*x*x-x-2" then I got "error: ‘fVal’ was not declared in this scope"
Lines 54-57 can be removed, they're not needed anymore - your expressions are strings now, not C++ code.

Also, please click in your output log, Ctrl+A to select all, Ctrl+C to copy it, and then Ctrl+V to paste here. You're not giving me the full error messages.
Last edited on
Ok, I use muparser without removing function f, I got

"Input function: x*x*x-x-2
Input interval start: 1
Input interval end: 2

Unexpected token "x" found at position 0.

RUN SUCCESSFUL (total time: 5s)"

My build say:

""/usr/bin/make" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
make[1]: Entering directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
"/usr/bin/make" -f nbproject/Makefile-Debug.mk dist/Debug/Cygwin-Windows/biseccion.exe
make[2]: Entering directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
mkdir -p build/Debug/Cygwin-Windows
rm -f build/Debug/Cygwin-Windows/main.o.d
g++ -c -g -MMD -MP -MF build/Debug/Cygwin-Windows/main.o.d -o build/Debug/Cygwin-Windows/main.o main.cpp
mkdir -p dist/Debug/Cygwin-Windows
g++ -o dist/Debug/Cygwin-Windows/biseccion build/Debug/Cygwin-Windows/main.o build/Debug/Cygwin-Windows/muParser.o build/Debug/Cygwin-Windows/muParserBase.o build/Debug/Cygwin-Windows/muParserBytecode.o build/Debug/Cygwin-Windows/muParserCallback.o build/Debug/Cygwin-Windows/muParserDLL.o build/Debug/Cygwin-Windows/muParserError.o build/Debug/Cygwin-Windows/muParserInt.o build/Debug/Cygwin-Windows/muParserTest.o build/Debug/Cygwin-Windows/muParserTokenReader.o
make[2]: Leaving directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
make[1]: Leaving directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'


BUILD SUCCESSFUL (total time: 1s)"

If I replace "x*x*x-x-2" for "funcion", I got:

"/usr/bin/make" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
make[1]: Entering directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
"/usr/bin/make" -f nbproject/Makefile-Debug.mk dist/Debug/Cygwin-Windows/biseccion.exe
make[2]: Entering directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
mkdir -p build/Debug/Cygwin-Windows
rm -f build/Debug/Cygwin-Windows/main.o.d
g++ -c -g -MMD -MP -MF build/Debug/Cygwin-Windows/main.o.d -o build/Debug/Cygwin-Windows/main.o main.cpp
main.cpp: In function ‘double f(double)’:
main.cpp:56:16: error: cannot convert ‘std::string’ to ‘double’ in return
nbproject/Makefile-Debug.mk:75: recipe for target `build/Debug/Cygwin-Windows/main.o' failed
make[2]: *** [build/Debug/Cygwin-Windows/main.o] Error 1
make[2]: Leaving directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
nbproject/Makefile-Debug.mk:68: recipe for target `.build-conf' failed
make[1]: *** [.build-conf] Error 2
make[1]: Leaving directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
nbproject/Makefile-impl.mk:39: recipe for target `.build-impl' failed
make: *** [.build-impl] Error 2


BUILD FAILED (exit value 2,, total time: 757ms)

If I replace "x*x*x-x-2" for "fVal" I got

"/usr/bin/make" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
make[1]: Entering directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
"/usr/bin/make" -f nbproject/Makefile-Debug.mk dist/Debug/Cygwin-Windows/biseccion.exe
make[2]: Entering directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
mkdir -p build/Debug/Cygwin-Windows
rm -f build/Debug/Cygwin-Windows/main.o.d
g++ -c -g -MMD -MP -MF build/Debug/Cygwin-Windows/main.o.d -o build/Debug/Cygwin-Windows/main.o main.cpp
main.cpp: In function ‘double f(double)’:
main.cpp:56:16: error: ‘fVal’ was not declared in this scope
nbproject/Makefile-Debug.mk:75: recipe for target `build/Debug/Cygwin-Windows/main.o' failed
make[2]: *** [build/Debug/Cygwin-Windows/main.o] Error 1
make[2]: Leaving directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
nbproject/Makefile-Debug.mk:68: recipe for target `.build-conf' failed
make[1]: *** [.build-conf] Error 2
make[1]: Leaving directory `/cygdrive/c/Users/Angel/Documents/NetBeansProjects/Biseccion'
nbproject/Makefile-impl.mk:39: recipe for target `.build-impl' failed
make: *** [.build-impl] Error 2


BUILD FAILED (exit value 2,, total time: 753ms)

Now, I think I can't remove function f (lines 54-57) if I do it, then how I'm gonna evaluate f(a) and f(b), needed for bisection method?
Have you considered that perhaps the issue is that you have not told muparser what 'x' is? It does not know if it is a variable, function, etc.

Ashir wrote:
Now, I think I can't remove function f (lines 54-57) if I do it, then how I'm gonna evaluate f(a) and f(b), needed for bisection method?
You evaluate the function the user types in, not the function you write in your code.
Ooooohhh, my men, you made light into the darkness!!!

You were right, muparser never knew what x was.

I had to

parser.DefineVar("x", &fVal);

"x" instead of "funcion".

And of course

1
2
3
4
 double f(double x_fVal)
 {
        return x_fVal;
 }


But now I have a problem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <muParser.h>
#include <muParserBase.h>
#include <muParserBytecode.h>
#include <muParserCallback.h>
#include <muParserDef.h>
#include <muParserError.h>
#include <muParserFixes.h>
#include <muParserStack.h>
#include <muParserToken.h>
#include <muParserTokenReader.h>
using namespace mu;
using namespace std;
double f(double x_fVal);
double biseccion(double a, double b, double tolerancia, int maxiter);
string funcion;
mu::Parser parser;
int main()
{
    try
    {
    double a, b, raiz;
    double tolerancia=0.00000;
    int maxiter=25;
    double fVal=0;
    
    
    cout << "Ingrese la funcion: ";
    cin >> funcion;
    
    Parser p;
    p.DefineVar("x", &fVal);    
    p.SetExpr(funcion);
    fVal = p.Eval();
    
    cout << fVal;
    
    cout << "Ingrese inicio del intervalo: ";
    cin >> a;
    cout << "Ingrese final del intervalo: ";
    cin >> b;
    cout << "\n";
    
    

    cout << "  # de"<<"\n"<<"Iteracion"<<"\t"<<"   A"<<"\t"<<"   B"<<"\t"<<"   C"<<"\t"<<"   f(c)"<<endl;
    raiz=biseccion(a,b,tolerancia,maxiter);
    cout << "\n";
    cout << "La raiz es: "<< raiz <<endl;
    cout << fVal;
    return 0;
    }  
        catch (Parser::exception_type &e)
    {
     std::cout << e.GetMsg() << endl;
    }
    
}
 
 double f(double x_fVal)
 {
        return x_fVal;
 }
 

 
 double biseccion(double a, double b, double tolerancia, int maxiter)
 {
        double c;
        int numiter=1;
        do
        {
            c=(a+b)/2;
            if(f(a)*f(c)<0)
            {
               b=c;
            }
            else
            {
               a=c;
            }
            cout<<"     "<<numiter<<"\t"<<"\t"<<a<<"\t"<<b<<"\t"<<c<<"\t"<<f(c)<<endl;
            numiter++;
         }
         while((abs(f(c))>tolerancia)&&(numiter<maxiter));
         return c;
}


If I input "x*x*x-x-2" using that code, fVal takes only "-2". Any idea why?
Because "fVal" is 0, and 0*0*0-0-2 is -2?
It really has sense...

Shouldn't muparser fill fVal with "x*x*x-x-2"?, that's the purpose of the parser, right?
The purpose of the parser is to take fVal and plug it into x in the expression.
Pages: 12