You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@stdcxx.apache.org by "Martin Sebor (JIRA)" <ji...@apache.org> on 2006/06/28 21:55:30 UTC

[jira] Created: (STDCXX-239) std::num_get::do_get() cannot parse nan, infinity

std::num_get::do_get() cannot parse nan, infinity
-------------------------------------------------

         Key: STDCXX-239
         URL: http://issues.apache.org/jira/browse/STDCXX-239
     Project: C++ Standard Library
        Type: New Feature

  Components: 22. Localization  
    Versions: 4.1.2, 4.1.3    
 Environment: all
    Reporter: Martin Sebor


Moved from the Rogue Wave bug tracking database:

****Created By: sebor @ Apr 04, 2000 07:13:59 PM****
The num_get<> facet's do_get() members  fail to take the special strings [-]inf[inity] and [-]nan into account. The facet reports an error when it encounters such strings. See 7.19.6.1 and 7.19.6.2 of C99 for a list of allowed strings.

The fix for this will not be trivial due to the messy implementation of the facets. It might be easier just to rewrite them from scratch.

The testcase below demonstrates the incorrect behavior. Modified test case added as tests/regress/src/test_issue22564.cpp - see p4 describe 22408.

$ g++ ... test.cpp
$ a.out  0 1 inf infinity nan INF INFINITY NAN
sscanf("0", "%lf") --> 0.000000
num_get<>::do_get("0", ...) --> 0.000000
sscanf("1", "%lf") --> 1.000000
num_get<>::do_get("1", ...) --> 1.000000
sscanf("inf", "%lf") --> inf
num_get<>::do_get("inf", ...) --> error
sscanf("infinity", "%lf") --> inf
num_get<>::do_get("infinity", ...) --> error
sscanf("nan", "%lf") --> nan
num_get<>::do_get("nan", ...) --> error
sscanf("INF", "%lf") --> inf
num_get<>::do_get("INF", ...) --> error
sscanf("INFINITY", "%lf") --> inf
num_get<>::do_get("INFINITY", ...) --> error
sscanf("NAN", "%lf") --> nan
num_get<>::do_get("NAN", ...) --> error


$ cat test.cpp

#include <iostream>
#include <locale>
#include <stdio.h>
#include <string.h>

using namespace std;

int main (int argc, const char *argv[])
{
    num_get<char, const char*> nget;

    for (int i = 1; i != argc; ++i) {
        double x = 0, y = 0;

        ios::iostate err = ios::goodbit;

        nget.get (argv [i], argv [i] + strlen (argv [i]), cin, err, x);

        if (1 != sscanf (argv [i], "%lf", &y))
            printf ("sscanf(\"%s\", \"%%lf\") --> error\n", argv [i]);
        else
            printf ("sscanf(\"%s\", \"%%lf\") --> %f\n", argv [i], y);

        if ((ios::failbit | ios::badbit) & err)
            printf ("num_get<>::do_get(\"%s\", ...) --> error\n", argv [i]);
        else
            printf ("num_get<>::do_get(\"%s\", ...) --> %f\n", argv [i], x);
    }
}

****Modified By: sebor @ Apr 09, 2000 09:31:49 PM****
Fixed with p4 describe 22544. Test case fixed with p4 describe 22545. Closed.

****Modified By: leroy @ Mar 30, 2001 03:09:11 PM****
Change 22544 by sebor@sebor_dev_killer on 2000/04/09 20:30:50

               Added support for inf[inity] and nan[(n-char-sequence)] as described
               in 7.19.6.1, p8 of C99.
               nan(n-char-sequence) currently treated the same as nan due to poor
               implementation of std::num_get<> and supporting classes - fix requires
               at least a partial rewrite of the facet.

               Resolves Onyx #22564 (and the duplicate #22601).

Affected files ...

... //stdlib2/dev/source/src/include/rw/numbrw#17 edit
... //stdlib2/dev/source/src/include/rw/numbrw.cc#12 edit
... //stdlib2/dev/source/vendor.cpp#17 edit

****Modified By: sebor @ Apr 03, 2001 08:46:50 PM****
It looks like this is actually not a bug and the fix is wrong (even as an extension). Here's some background...

Subject: Is this a permissible extension?
Date: Thu, 8 Feb 2001 18:16:18 -0500 (EST)
From: Andrew Koenig <ar...@research.att.com>
Reply-To: c++std-lib@research.att.com

To: C++ libraries mailing list
Message c++std-lib-8281

Suppose we execute

        double x;

        std::cin >> x;

at a point where the input stream contains

   NaN

followed perhaps by other characters.

One might plausibly expect an implementation to set x to NaN
on an implementation that supports IEEE floating-point.

Surely the standard cannot mandate such behavior, because not
every implementation knows what NaN is.  However, on an implementation
that does support NaN, is such behavior a permitted extension?

My first attempt at an answer is no, because if I track through the
standard, I find that the behavior of this statement is defined
as being identical to the behavior of strtod in c89, and that behavior
requires at least one digit in the input in order for the intput to
be valid.  However, I might have missed something.  Have I?

****Modified By: sebor @ Apr 03, 2001 08:48:03 PM****
Subject: Re: Is this a permissible extension?
Date: Fri, 09 Feb 2001 09:28:25 -0800
From: Matt Austern <au...@research.att.com>
Reply-To: c++std-lib@research.att.com
Organization: AT&T Labs - Research
References: 1 , 2

To: C++ libraries mailing list
Message c++std-lib-8284

Andrew Koenig wrote:

> Fred> In "C" locale, only decimal floating-point constants are valid.
> Fred> So, no NaN nor Infinity is allowed.
> 
> Yes -- I was talking about the default locale.

Actually, I think that strtod isn't the important part, at least for
discussing C++.  I think that this is an illegal extension in all
named locales.

First, let me explain why I said *named* locales.  If you construct
a locale with locale("foo"), the way it works is that the locale is
built up out of _byname facets instead of base class facets.  Except
that not all facets have _byname derived classes, so in some cases
you've still got the default behavior from the facet base class.  

One of the facets that has no _byname variant is num_get<>.  So if I
can construct an argument that the documented behavior of num_get<>
precludes this extension, I have also proved that this extension is
impossible in any named locale.  This argument does not apply to
arbitrary locales, since an arbitrary locale may replace any base
class facet that with a facet that inherits from it.

OK, now the argument I promised, saying that num_get<> can't recognize
the character string "NaN".

22.2.2.1.2, paragraph 2: num_get's overloaded conversion function, 
num_get::do_get(), works in three stages.

(1) It determines conversion specifiers.  We're OK so far.
(2) It accumulates characters from a provided input character.
(3) It uses the conversion specifiers and the characters it has
accumulated to produce a number.

Stage 2 is the crucial one.  it's described in 22.2.2.1.2/8-10, in
great detail.

For each character,
  (a) We get it from a supplied input iterator.
  (b) We look it up in a lookup table whose contents are prescribed
      by the standard.  (This has to do with wide characters, but there
      is no exception for the special case where you're reading narrow
      characters.)
  (c) If a character is found in the lookup table, or if it's a decimal
      point or a thousands sep, then it's checked to see if it can 
      legally appear in the number at that point.  If so, we keep 
      acumulating characters.

The characters in the lookup table are "0123456789abcdefABCDEF+-".
Library issue 221 would amend that to "0123456789abcdefxABCDEFX+-".
"N" isn't present in the lookup table, so stage 2 of num_get<>::do_get()
is not permitted to read the character sequence "NaN".

If you want to argue that num_get<>::do_get() is overspecified, I 
wouldn't disagree too violently.

                        --Matt

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira


[jira] Updated: (STDCXX-239) std::num_get::do_get() cannot parse nan, infinity

Posted by "Martin Sebor (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/STDCXX-239?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Martin Sebor updated STDCXX-239:
--------------------------------

    Affects Version/s: 4.1.4
        Fix Version/s: 4.3

Added 4.1.4 to the set of affected versions and scheduled for 4.3 (I expect this feature to be bigger than what would be appropriate for a patch release, possibly even too big for a minor release).

> std::num_get::do_get() cannot parse nan, infinity
> -------------------------------------------------
>
>                 Key: STDCXX-239
>                 URL: https://issues.apache.org/jira/browse/STDCXX-239
>             Project: C++ Standard Library
>          Issue Type: New Feature
>          Components: 22. Localization
>    Affects Versions: 4.1.2, 4.1.3, 4.1.4
>         Environment: all
>            Reporter: Martin Sebor
>             Fix For: 4.3
>
>
> Moved from the Rogue Wave bug tracking database:
> ****Created By: sebor @ Apr 04, 2000 07:13:59 PM****
> The num_get<> facet's do_get() members  fail to take the special strings [-]inf[inity] and [-]nan into account. The facet reports an error when it encounters such strings. See 7.19.6.1 and 7.19.6.2 of C99 for a list of allowed strings.
> The fix for this will not be trivial due to the messy implementation of the facets. It might be easier just to rewrite them from scratch.
> The testcase below demonstrates the incorrect behavior. Modified test case added as tests/regress/src/test_issue22564.cpp - see p4 describe 22408.
> $ g++ ... test.cpp
> $ a.out  0 1 inf infinity nan INF INFINITY NAN
> sscanf("0", "%lf") --> 0.000000
> num_get<>::do_get("0", ...) --> 0.000000
> sscanf("1", "%lf") --> 1.000000
> num_get<>::do_get("1", ...) --> 1.000000
> sscanf("inf", "%lf") --> inf
> num_get<>::do_get("inf", ...) --> error
> sscanf("infinity", "%lf") --> inf
> num_get<>::do_get("infinity", ...) --> error
> sscanf("nan", "%lf") --> nan
> num_get<>::do_get("nan", ...) --> error
> sscanf("INF", "%lf") --> inf
> num_get<>::do_get("INF", ...) --> error
> sscanf("INFINITY", "%lf") --> inf
> num_get<>::do_get("INFINITY", ...) --> error
> sscanf("NAN", "%lf") --> nan
> num_get<>::do_get("NAN", ...) --> error
> $ cat test.cpp
> #include <iostream>
> #include <locale>
> #include <stdio.h>
> #include <string.h>
> using namespace std;
> int main (int argc, const char *argv[])
> {
>     num_get<char, const char*> nget;
>     for (int i = 1; i != argc; ++i) {
>         double x = 0, y = 0;
>         ios::iostate err = ios::goodbit;
>         nget.get (argv [i], argv [i] + strlen (argv [i]), cin, err, x);
>         if (1 != sscanf (argv [i], "%lf", &y))
>             printf ("sscanf(\"%s\", \"%%lf\") --> error\n", argv [i]);
>         else
>             printf ("sscanf(\"%s\", \"%%lf\") --> %f\n", argv [i], y);
>         if ((ios::failbit | ios::badbit) & err)
>             printf ("num_get<>::do_get(\"%s\", ...) --> error\n", argv [i]);
>         else
>             printf ("num_get<>::do_get(\"%s\", ...) --> %f\n", argv [i], x);
>     }
> }
> ****Modified By: sebor @ Apr 09, 2000 09:31:49 PM****
> Fixed with p4 describe 22544. Test case fixed with p4 describe 22545. Closed.
> ****Modified By: leroy @ Mar 30, 2001 03:09:11 PM****
> Change 22544 by sebor@sebor_dev_killer on 2000/04/09 20:30:50
>                Added support for inf[inity] and nan[(n-char-sequence)] as described
>                in 7.19.6.1, p8 of C99.
>                nan(n-char-sequence) currently treated the same as nan due to poor
>                implementation of std::num_get<> and supporting classes - fix requires
>                at least a partial rewrite of the facet.
>                Resolves Onyx #22564 (and the duplicate #22601).
> Affected files ...
> ... //stdlib2/dev/source/src/include/rw/numbrw#17 edit
> ... //stdlib2/dev/source/src/include/rw/numbrw.cc#12 edit
> ... //stdlib2/dev/source/vendor.cpp#17 edit
> ****Modified By: sebor @ Apr 03, 2001 08:46:50 PM****
> It looks like this is actually not a bug and the fix is wrong (even as an extension). Here's some background...
> Subject: Is this a permissible extension?
> Date: Thu, 8 Feb 2001 18:16:18 -0500 (EST)
> From: Andrew Koenig <ar...@research.att.com>
> Reply-To: c++std-lib@research.att.com
> To: C++ libraries mailing list
> Message c++std-lib-8281
> Suppose we execute
>         double x;
>         std::cin >> x;
> at a point where the input stream contains
>    NaN
> followed perhaps by other characters.
> One might plausibly expect an implementation to set x to NaN
> on an implementation that supports IEEE floating-point.
> Surely the standard cannot mandate such behavior, because not
> every implementation knows what NaN is.  However, on an implementation
> that does support NaN, is such behavior a permitted extension?
> My first attempt at an answer is no, because if I track through the
> standard, I find that the behavior of this statement is defined
> as being identical to the behavior of strtod in c89, and that behavior
> requires at least one digit in the input in order for the intput to
> be valid.  However, I might have missed something.  Have I?
> ****Modified By: sebor @ Apr 03, 2001 08:48:03 PM****
> Subject: Re: Is this a permissible extension?
> Date: Fri, 09 Feb 2001 09:28:25 -0800
> From: Matt Austern <au...@research.att.com>
> Reply-To: c++std-lib@research.att.com
> Organization: AT&T Labs - Research
> References: 1 , 2
> To: C++ libraries mailing list
> Message c++std-lib-8284
> Andrew Koenig wrote:
> > Fred> In "C" locale, only decimal floating-point constants are valid.
> > Fred> So, no NaN nor Infinity is allowed.
> > 
> > Yes -- I was talking about the default locale.
> Actually, I think that strtod isn't the important part, at least for
> discussing C++.  I think that this is an illegal extension in all
> named locales.
> First, let me explain why I said *named* locales.  If you construct
> a locale with locale("foo"), the way it works is that the locale is
> built up out of _byname facets instead of base class facets.  Except
> that not all facets have _byname derived classes, so in some cases
> you've still got the default behavior from the facet base class.  
> One of the facets that has no _byname variant is num_get<>.  So if I
> can construct an argument that the documented behavior of num_get<>
> precludes this extension, I have also proved that this extension is
> impossible in any named locale.  This argument does not apply to
> arbitrary locales, since an arbitrary locale may replace any base
> class facet that with a facet that inherits from it.
> OK, now the argument I promised, saying that num_get<> can't recognize
> the character string "NaN".
> 22.2.2.1.2, paragraph 2: num_get's overloaded conversion function, 
> num_get::do_get(), works in three stages.
> (1) It determines conversion specifiers.  We're OK so far.
> (2) It accumulates characters from a provided input character.
> (3) It uses the conversion specifiers and the characters it has
> accumulated to produce a number.
> Stage 2 is the crucial one.  it's described in 22.2.2.1.2/8-10, in
> great detail.
> For each character,
>   (a) We get it from a supplied input iterator.
>   (b) We look it up in a lookup table whose contents are prescribed
>       by the standard.  (This has to do with wide characters, but there
>       is no exception for the special case where you're reading narrow
>       characters.)
>   (c) If a character is found in the lookup table, or if it's a decimal
>       point or a thousands sep, then it's checked to see if it can 
>       legally appear in the number at that point.  If so, we keep 
>       acumulating characters.
> The characters in the lookup table are "0123456789abcdefABCDEF+-".
> Library issue 221 would amend that to "0123456789abcdefxABCDEFX+-".
> "N" isn't present in the lookup table, so stage 2 of num_get<>::do_get()
> is not permitted to read the character sequence "NaN".
> If you want to argue that num_get<>::do_get() is overspecified, I 
> wouldn't disagree too violently.
>                         --Matt

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.