The input operator for Rational numbers

Discussion in 'C++' started by Saeed Amrollahi, Nov 15, 2009.

  1. Hi

    I am going to design and implement a typical library for rational
    numbers, something like
    Boost.Rational. My class is actually implemented as a template, in a
    similar manner to the standard complex class.
    I want to handle Whole numbers like rational numbers; As you know,
    from point of math view
    whole numbers are subset of rational numbers, for example 3 is 3/1.
    I like to read both kind of numbers (whole and fraction) in a single
    operator>> function. I mean
    I want to handle
    a
    a/b
    together. I finally ended with an assumption: Immediately, after
    numerator, I should get '/':
    template<class T>
    std::istream& operator>>(std::istream& is, rational<T>& r)
    {
    /*
    handle the following foramts:
    n/d
    n
    */
    T n, d;
    char c = 0; // for '/'
    is >> n;
    if (is.good()) {
    is.get(c);
    }
    if (c == '/') { // fraction
    if (is.good())
    is >> d;
    }
    else if (std::isspace(c) || is.rdstate() & std::ios_base::eofbit)
    { // whole number
    d = 1;
    }
    else {
    is.clear(std::ios_base::badbit); // set state
    }

    if (is) // everything is good
    r = rational<T>(n, d);

    return is;
    }

    I know, my code may be inefficient.
    Any suggestion for better/more elegant handling different formats and
    better efficiency?

    Thanks in advance,
    -- Saeed Amrollahi
     
    Saeed Amrollahi, Nov 15, 2009
    #1
    1. Advertising

  2. Saeed Amrollahi

    James Kanze Guest

    On Nov 15, 4:07 pm, Saeed Amrollahi <> wrote:
    > I am going to design and implement a typical library for
    > rational numbers, something like Boost.Rational. My class is
    > actually implemented as a template, in a similar manner to the
    > standard complex class. I want to handle Whole numbers like
    > rational numbers; As you know, from point of math view whole
    > numbers are subset of rational numbers, for example 3 is 3/1.
    > I like to read both kind of numbers (whole and fraction) in a
    > single operator>> function. I mean I want to handle
    > a
    > a/b
    > together. I finally ended with an assumption: Immediately,
    > after numerator, I should get '/':


    > template<class T>
    > std::istream& operator>>(std::istream& is, rational<T>& r)
    > {
    > /*
    > handle the following foramts:
    > n/d
    > n
    > */
    > T n, d;
    > char c = 0; // for '/'
    > is >> n;
    > if (is.good()) {
    > is.get(c);
    > }
    > if (c == '/') { // fraction
    > if (is.good())
    > is >> d;
    > }
    > else if (std::isspace(c) || is.rdstate() & std::ios_base::eofbit)
    > { // whole number
    > d = 1;
    > }
    > else {
    > is.clear(std::ios_base::badbit); // set state
    > }
    > if (is) // everything is good
    > r = rational<T>(n, d);
    > return is;
    > }


    > I know, my code may be inefficient.
    > Any suggestion for better/more elegant handling different
    > formats and better efficiency?


    I'm not too sure about your error handling, and your logic. If
    nothing else, you're extracting one character too many when
    reading just a whole number. (Think of something like 3+1/3.)
    What's wrong with something simple like:

    T n;
    is >> n;
    T d(1); // T must support conversion from int.
    if ( is.peek() == '/' ) {
    is.get(); // extract '/'
    is >> d;
    }
    if ( is ) {
    r = rational<T>( n, d );
    }
    return is;

    This leaves all of the error handling up to >>T, and seems
    overall the simplest solution.

    --
    James Kanze
     
    James Kanze, Nov 16, 2009
    #2
    1. Advertising

  3. On Nov 16, 12:01 pm, James Kanze <> wrote:
    > On Nov 15, 4:07 pm, Saeed Amrollahi <> wrote:
    >
    >
    >
    >
    >
    > > I am going to design and implement a typical library for
    > > rational numbers, something like Boost.Rational. My class is
    > > actually implemented as a template, in a similar manner to the
    > > standard complex class.  I want to handle Whole numbers like
    > > rational numbers; As you know, from point of math view whole
    > > numbers are subset of rational numbers, for example 3 is 3/1.
    > > I like to read both kind of numbers (whole and fraction) in a
    > > single operator>> function. I mean I want to handle
    > >   a
    > >   a/b
    > > together. I finally ended with an assumption: Immediately,
    > > after numerator, I should get '/':
    > > template<class T>
    > > std::istream& operator>>(std::istream& is, rational<T>& r)
    > > {
    > >   /*
    > >     handle the following foramts:
    > >     n/d
    > >     n
    > >   */
    > >   T n, d;
    > >   char c = 0; // for '/'
    > >   is >> n;
    > >   if (is.good()) {
    > >     is.get(c);
    > >   }
    > >   if (c == '/') { // fraction
    > >     if (is.good())
    > >         is >> d;
    > >   }
    > >  else if (std::isspace(c) || is.rdstate() & std::ios_base::eofbit)
    > > { // whole number
    > >     d = 1;
    > >   }
    > >   else {
    > >     is.clear(std::ios_base::badbit); // set state
    > >   }
    > >   if (is) // everything is good
    > >     r = rational<T>(n, d);
    > >   return is;
    > > }
    > > I know, my code may be inefficient.
    > > Any suggestion for better/more elegant handling different
    > > formats and better efficiency?

    >
    > I'm not too sure about your error handling, and your logic.  If
    > nothing else, you're extracting one character too many when
    > reading just a whole number.  (Think of something like 3+1/3.)
    > What's wrong with something simple like:
    >
    >     T n;
    >     is >> n;
    >     T d(1);    //  T must support conversion from int.
    >     if ( is.peek() == '/' ) {
    >         is.get();       //  extract '/'
    >         is >> d;
    >     }
    >     if ( is ) {
    >         r = rational<T>( n, d );
    >     }
    >     return is;
    >
    > This leaves all of the error handling up to >>T, and seems
    > overall the simplest solution.
    >
    > --
    > James Kanze- Hide quoted text -
    >
    > - Show quoted text -


    Hi James
    Thank you for your feedback.
    The template parameter T is an Integral type.
    My main problem is:
    Is there any solution to read a fraction and whole number in formatted
    way
    rather than using unformatted (get function)? I guess there is no way.
    So I assumed, if user wants to enter a whole number, (s)he have to
    enter in
    one line. So, I use isspace() and ios_base::eofbit.
    for a fraction my assumption is: if user wants to enter a fraction, (s)
    he have to
    enter '/' immediately after numerator. Your code somehow reflects
    that.
    Of course your code is simple and elegant and my code is somehow
    sloppy.

    Please throw light.
    -- Saeed Amrollahi
     
    Saeed Amrollahi, Nov 16, 2009
    #3
  4. Saeed Amrollahi

    James Kanze Guest

    On Nov 16, 9:26 am, Saeed Amrollahi <> wrote:
    > On Nov 16, 12:01 pm, James Kanze <> wrote:


    [...]
    > > I'm not too sure about your error handling, and your logic.
    > > If nothing else, you're extracting one character too many
    > > when reading just a whole number. (Think of something like
    > > 3+1/3.) What's wrong with something simple like:


    > > T n;
    > > is >> n;
    > > T d(1); // T must support conversion from int.
    > > if ( is.peek() == '/' ) {
    > > is.get(); // extract '/'
    > > is >> d;
    > > }
    > > if ( is ) {
    > > r = rational<T>( n, d );
    > > }
    > > return is;


    > > This leaves all of the error handling up to >>T, and seems
    > > overall the simplest solution.



    > Thank you for your feedback.
    > The template parameter T is an Integral type.


    I more or less guessed that:). Although you might want to ask
    yourself what will happen if someone instantiates your template
    on double, or even std::string.

    > My main problem is:
    > Is there any solution to read a fraction and whole number in
    > formatted way rather than using unformatted (get function)?


    I'm not sure what you really mean by "formatted" way? You want
    to look at a single character, without extracting it;
    istream::peek is the function which does that.

    There is one weakness in my quicky solution above: it doesn't
    allow white space before the '/', but allows it after. This
    could easily be fixed by verifying that the character after the
    '/' is not white space (getting it, again, using peek()), or by
    skipping white space before checking for the '/'.

    > I guess there is no way. So I assumed, if user wants to enter
    > a whole number, (s)he have to enter in one line.


    Not with the above. The above will read a number. If the
    character immediately following the number is a '/', it skips
    this, and reads a second number. Otherwise, it stops with the
    number, removing no more characters.

    > So, I use isspace() and ios_base::eofbit.


    That was the point I didn't fully understand in the original
    code. Is the fact that you only read the numerator (and use 1
    for the denominator) determined by the fact that the first
    number is immediately followed by a '/', or by the fact that it
    was followed by white space or the end of file. In other words,
    what was the desired behavior when reading something like:
    43,x
    Should the extractor extract the 43, return 43/1, and leave the
    input positionned on the ',', or should it set failbit to
    indicate a format error on input. (My version does the first.)

    > for a fraction my assumption is: if user wants to enter a
    > fraction, (s) he have to enter '/' immediately after
    > numerator. Your code somehow reflects that.


    My code does that exactly. If the first character after the
    number in the stream is a '/', it skips it, and attempts to read
    a denominator. Otherwise, it uses the default value 1 as
    denominator.

    --
    James Kanze
     
    James Kanze, Nov 16, 2009
    #4
  5. On Nov 16, 9:20 pm, James Kanze <> wrote:
    > On Nov 16, 9:26 am, Saeed Amrollahi <> wrote:
    >
    > > On Nov 16, 12:01 pm, James Kanze <> wrote:

    >
    >     [...]
    >
    >
    >
    >
    >
    > > > I'm not too sure about your error handling, and your logic.
    > > > If nothing else, you're extracting one character too many
    > > > when reading just a whole number.  (Think of something like
    > > > 3+1/3.) What's wrong with something simple like:
    > > >     T n;
    > > >     is >> n;
    > > >     T d(1);    //  T must support conversion from int.
    > > >     if ( is.peek() == '/' ) {
    > > >         is.get();       //  extract '/'
    > > >         is >> d;
    > > >     }
    > > >     if ( is ) {
    > > >         r = rational<T>( n, d );
    > > >     }
    > > >     return is;
    > > > This leaves all of the error handling up to >>T, and seems
    > > > overall the simplest solution.

    > > Thank you for your feedback.
    > > The template parameter T is an Integral type.

    >
    > I more or less guessed that:).  Although you might want to ask
    > yourself what will happen if someone instantiates your template
    > on double, or even std::string.
    >
    > > My main problem is:
    > > Is there any solution to read a fraction and whole number in
    > > formatted way rather than using unformatted (get function)?

    >
    > I'm not sure what you really mean by "formatted" way?  You want
    > to look at a single character, without extracting it;
    > istream::peek is the function which does that.
    >
    > There is one weakness in my quicky solution above: it doesn't
    > allow white space before the '/', but allows it after.  This
    > could easily be fixed by verifying that the character after the
    > '/' is not white space (getting it, again, using peek()), or by
    > skipping white space before checking for the '/'.
    >
    > > I guess there is no way.  So I assumed, if user wants to enter
    > > a whole number, (s)he have to enter in one line.

    >
    > Not with the above.  The above will read a number.  If the
    > character immediately following the number is a '/', it skips
    > this, and reads a second number.  Otherwise, it stops with the
    > number, removing no more characters.
    >
    > > So, I use isspace() and ios_base::eofbit.

    >
    > That was the point I didn't fully understand in the original
    > code.  Is the fact that you only read the numerator (and use 1
    > for the denominator) determined by the fact that the first
    > number is immediately followed by a '/', or by the fact that it
    > was followed by white space or the end of file.  In other words,
    > what was the desired behavior when reading something like:
    >     43,x
    > Should the extractor extract the 43, return 43/1, and leave the
    > input positionned on the ',', or should it set failbit to
    > indicate a format error on input.  (My version does the first.)
    >
    > > for a fraction my assumption is: if user wants to enter a
    > > fraction, (s) he have to enter '/' immediately after
    > > numerator. Your code somehow reflects that.

    >
    > My code does that exactly.  If the first character after the
    > number in the stream is a '/', it skips it, and attempts to read
    > a denominator.  Otherwise, it uses the default value 1 as
    > denominator.
    >
    > --
    > James Kanze- Hide quoted text -
    >
    > - Show quoted text -


    Thanks for your feedback
    -- Saeed Amrollahi
     
    Saeed Amrollahi, Nov 17, 2009
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Brian van den Broek
    Replies:
    2
    Views:
    408
    Dan Bishop
    Jul 5, 2005
  2. Brian van den Broek
    Replies:
    4
    Views:
    612
  3. Paul Rubin

    rational numbers

    Paul Rubin, Jan 17, 2006, in forum: Python
    Replies:
    3
    Views:
    353
    =?ISO-8859-1?Q?Sch=FCle_Daniel?=
    Jan 17, 2006
  4. Facundo Batista

    Re: Rational Numbers

    Facundo Batista, Jan 11, 2007, in forum: Python
    Replies:
    15
    Views:
    594
    Nick Maclaren
    Jan 14, 2007
  5. Facundo Batista

    Re: Rational Numbers

    Facundo Batista, Jan 12, 2007, in forum: Python
    Replies:
    3
    Views:
    290
    Nick Maclaren
    Jan 13, 2007
Loading...

Share This Page