stringstream and Scientific Notation

334 views
Skip to first unread message

Michael Betancourt

unread,
Jun 7, 2013, 7:01:10 AM6/7/13
to stan...@googlegroups.com
I tracked down the bug in bin/print, and it occurs when string stream tries to parse a number in scientific notation with three digits in the exponent, for example "ss >> 1.78358e-321".  The stream fails, and then further uses of operator>> read from random memory, hence the incorrect results.

This looks like a bug in stringstream (two digits in the exponent parses just fine) -- does anyone have any problem with my thresholding values in mcmc_writer?  Basically anything below 1e-50 would be set to zero.

Marcus Brubaker

unread,
Jun 7, 2013, 10:58:18 AM6/7/13
to stan...@googlegroups.com
Hmmm, that seems like fixing the wrong problem.

If this is a bug in stringstream parsing, what happens when you use something like strtod() or atof()?  Not "pure C++" style, but at least it's working around the bug itself.

Cheers,
Marcus


On Fri, Jun 7, 2013 at 7:01 AM, Michael Betancourt <betan...@gmail.com> wrote:
I tracked down the bug in bin/print, and it occurs when string stream tries to parse a number in scientific notation with three digits in the exponent, for example "ss >> 1.78358e-321".  The stream fails, and then further uses of operator>> read from random memory, hence the incorrect results.

This looks like a bug in stringstream (two digits in the exponent parses just fine) -- does anyone have any problem with my thresholding values in mcmc_writer?  Basically anything below 1e-50 would be set to zero.

--
You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stan-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Michael Betancourt

unread,
Jun 7, 2013, 12:14:55 PM6/7/13
to stan...@googlegroups.com
I don't have a strong opinion either way, but using another parser would complicate the code nontrivially and remove much of the motivation for using a stringstream.

Bob Carpenter

unread,
Jun 7, 2013, 2:01:17 PM6/7/13
to stan...@googlegroups.com
Curious. The number is between min() and denorm_min() for doubles:

std::cout << "1.78358e-321=" << 1.78358e-321 << std::endl;
std::cout << "min=" << std::numeric_limits<double>::min() << std::endl;
std::cout << "denorm min=" << std::numeric_limits<double>::denorm_min() << std::endl;

prints:

1.78358e-321=1.78358e-321
min=2.22507e-308
denorm min=4.94066e-324

My go-to reference

http://www.cplusplus.com/reference/limits/numeric_limits/

says min() is:

Minimum finite value.
For floating types with denormalization (variable number of exponent bits):
minimum positive normalized value.
Equivalent to CHAR_MIN, SCHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN, FLT_MIN,
DBL_MIN, LDBL_MIN or 0, depending on type.

and for denorm_min(), it says:

Minimum positive denormalized value.
For types not allowing denormalized values: same as min().

I have no idea what denormalization is, but it looks relevant here.

- Bob

On 6/7/13 12:14 PM, Michael Betancourt wrote:
> I don't have a strong opinion either way, but using another parser would complicate the code nontrivially and remove
> much of the motivation for using a stringstream.
>
>
> On Fri, Jun 7, 2013 at 3:58 PM, Marcus Brubaker <marcus.a...@gmail.com <mailto:marcus.a...@gmail.com>> wrote:
>
> Hmmm, that seems like fixing the wrong problem.
>
> If this is a bug in stringstream parsing, what happens when you use something like strtod() or atof()? Not "pure
> C++" style, but at least it's working around the bug itself.
>
> Cheers,
> Marcus
>
>
> On Fri, Jun 7, 2013 at 7:01 AM, Michael Betancourt <betan...@gmail.com <mailto:betan...@gmail.com>> wrote:
>
> I tracked down the bug in bin/print, and it occurs when string stream tries to parse a number in scientific
> notation with three digits in the exponent, for example "ss >> 1.78358e-321". The stream fails, and then
> further uses of operator>> read from random memory, hence the incorrect results.
>
> This looks like a bug in stringstream (two digits in the exponent parses just fine) -- does anyone have any
> problem with my thresholding values in mcmc_writer? Basically anything below 1e-50 would be set to zero.
>
> --
> You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
> stan-dev+u...@googlegroups.com <mailto:stan-dev%2Bunsu...@googlegroups.com>.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
>
> --
> You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
> stan-dev+u...@googlegroups.com <mailto:stan-dev%2Bunsu...@googlegroups.com>.

Michael Betancourt

unread,
Jun 7, 2013, 2:11:13 PM6/7/13
to stan...@googlegroups.com
Honestly, it almost looks like someone hardcoded two digits in the exponent in the stringstream code.

Marcus Brubaker

unread,
Jun 7, 2013, 2:38:25 PM6/7/13
to stan...@googlegroups.com
In IEEE floating point, the number is represented in two parts.  The base number and the exponent, i.e., 1.423566 x 10^-123 (except in base 2) where 1.423566 is the base and -123 is, obviously, the exponent.

There are a certain number of bits given to represent the base and the exponent.  Once the maximum value of the exponent has been reached, that is basically the min value.  However, you can get a slight more range by allowing the base number to be denormalized.  I.E., if you write 0.0000001 x 10^-123, that is a denormalied base.

I would be surprised if this is related to what is going on here.

Cheers,
Marcus



        For more options, visit https://groups.google.com/groups/opt_out.



    --
    You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to

    For more options, visit https://groups.google.com/groups/opt_out.



--
You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stan-dev+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.



--
You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stan-dev+unsubscribe@googlegroups.com.

Bob Carpenter

unread,
Jun 7, 2013, 3:07:20 PM6/7/13
to stan...@googlegroups.com


On 6/7/13 2:11 PM, Michael Betancourt wrote:
> Honestly, it almost looks like someone hardcoded two digits in the exponent in the stringstream code.

But

ss << "2.22507e-308";
ss >> y;
std::cout << "y=" << y << std::endl;

prints

y=0

whereas using

ss << "2.22508e-308";

prints

y=2.22508e-308

so it looks like it's just numbers less than numeric_limits<double>::min()
and greater than numeric_limits<double>::denorm_min(). Recall:

min=2.22507e-308
denorm min=4.94066e-324

- Bob

Bob Carpenter

unread,
Jun 7, 2013, 3:08:45 PM6/7/13
to stan...@googlegroups.com
On 6/7/13 2:38 PM, Marcus Brubaker wrote:
> ...
> However, you can get a slight more range by allowing the base number
> to be denormalized. I.E., if you write 0.0000001 x 10^-123, that is a denormalied base.
>
> I would be surprised if this is related to what is going on here.

C++ is nothing if not full of surprises :-)

- Bob

Michael Betancourt

unread,
Jun 7, 2013, 3:55:14 PM6/7/13
to stan...@googlegroups.com
Huh -- when I try to read such a number (albeit in a comma separated list), operator>> flips the fail switch and y gets nonsense. Killing one of the digits in the exponent removes the problem.

If stringstream was giving 0 instead of some really tiny number we'd have no problem -- can anyone reproduce the failure of stringstream?
> --
> You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to stan-dev+u...@googlegroups.com.

Bob Carpenter

unread,
Jun 7, 2013, 4:42:46 PM6/7/13
to stan...@googlegroups.com
Yes. That's really lousy behavior. No idea what
the full spec is, so I don't know if it's a bug or if
input is undetermined after an error.

With:

std::stringstream ss;
double y1, y2;
std::string punct;
ss << "2.9e-200, 3.14";
ss >> y1 >> punct >> y2;
std::cout << "y1=" << y1 << "; y2=" << y2 << "; punct=" << punct << std::endl;

I get:

y1=2.9e-200; y2=3.14; punct=,

but with ss set to underflow,

ss << "2.9e-400, 3.14";

I get:

y1=0; y2=0; punct=

But then I tried first setting y1 and y2 and
noticed that in the error case you get no change to the variables.
So with

std::stringstream ss;
double y1 = 152, y2 = -3;
std::string punct;
ss << "2.9e-400, 3.14";
ss >> y1 >> punct >> y2;
std::cout << "y1=" << y1 << "; y2=" << y2 << "; punct=" << punct << std::endl;

I got:

y1=152; y2=-3; punct=

Same results under clang++ and g++ under -O1 and -O3 by the way.

- Bob

Jiqiang Guo

unread,
Jun 7, 2013, 6:53:06 PM6/7/13
to stan...@googlegroups.com
boost's lexical_cast seems to work. 

 double y1 = 110;
 y1 = boost::lexical_cast<double>("2.9e-400");
  std::cout << "y1=" << y1 << std::endl;

will give

y1=0

--
Jiqiang

To unsubscribe from this group and stop receiving emails from it, send an email to stan-dev+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.


--
You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stan-dev+unsubscribe@googlegroups.com.

Bob Carpenter

unread,
Jun 7, 2013, 10:48:11 PM6/7/13
to stan...@googlegroups.com
So can you just pull out a string and use this?

Is there an advantage to the Boost code over strtod()?

http://www.cplusplus.com/reference/cstdlib/strtod/

I don't like the ugly pointer arithmetic in strtod(), but
then I didn't cut my teeth on C.

- Bob

On 6/7/13 6:53 PM, Jiqiang Guo wrote:
> boost's lexical_cast seems to work.
>
> double y1 = 110;
> y1 = boost::lexical_cast<double>("2.9e-400");
> std::cout << "y1=" << y1 << std::endl;
>
> will give
>
> y1=0
>
> --
> Jiqiang
>
> On Jun 7, 2013, at 8:07 PM, Bob Carpenter <ca...@alias-i.com <mailto:ca...@alias-i.com>> wrote:
>
>
>
> On 6/7/13 2:11 PM, Michael Betancourt wrote:
>
> Honestly, it almost looks like someone hardcoded two digits in the exponent in the stringstream code.
>
>
> But
>
> ss << "2.22507e-308";
> ss >> y;
> std::cout << "y=" << y << std::endl;
>
> prints
>
> y=0
>
> whereas using
>
> ss << "2.22508e-308";
>
> prints
>
> y=2.22508e-308
>
> so it looks like it's just numbers less than numeric_limits<double>::min()
> and greater than numeric_limits<double>::__denorm_min(). Recall:
>
> min=2.22507e-308
> denorm min=4.94066e-324
>
> - Bob
>
>
> On Jun 7, 2013, at 12:01 PM, Michael Betancourt <betan...@gmail.com <mailto:betan...@gmail.com>> wrote:
>
> I tracked down the bug in bin/print, and it occurs when string stream tries to parse a number in
> scientific notation with three digits in the exponent, for example "ss >> 1.78358e-321". The stream
> fails, and then further uses of operator>> read from random memory, hence the incorrect results.
>
> This looks like a bug in stringstream (two digits in the exponent parses just fine) -- does anyone
> have any problem with my thresholding values in mcmc_writer? Basically anything below 1e-50 would
> be set to zero.
>
>
>
> --
> You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
> stan-dev+unsubscribe@__googlegroups.com <mailto:stan-dev%2Bunsu...@googlegroups.com>.
> For more options, visit https://groups.google.com/__groups/opt_out <https://groups.google.com/groups/opt_out>.
>
>
>
>
> --
> You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
> stan-dev+unsubscribe@__googlegroups.com <mailto:stan-dev%2Bunsu...@googlegroups.com>.
> For more options, visit https://groups.google.com/__groups/opt_out <https://groups.google.com/groups/opt_out>.
>
>
>
> --
> You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to stan-dev+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages