Reading and Writing float value of infinity to file.

J

Jim Langston

The output of the following program is:
1.#INF
1

But:
1.#INF
1.#INF

was expected and desired. How can I read a value of infinity from a stream?

#include <iostream>
#include <fstream>
#include <limits>

int main(void)
{
float Infinity;
Infinity = std::numeric_limits<float>::infinity();
std::cout << Infinity << "\n";

std::eek:fstream outf("test.txt");
if ( outf.is_open() )
outf << Infinity;

outf.close();

float Value = 0.0f;
std::ifstream inf("test.txt");
if ( inf.is_open() )
inf >> Value;

inf.close();

std::cout << Value << "\n";

return 0;
}
 
J

James Kanze

The output of the following program is:
1.#INF
1

was expected and desired. How can I read a value of infinity
from a stream?

According to the current C++ standard, there is no infinity, so
you're in the realm of implementation defined, if not undefined
behavior. Presumably, however, the next version of the standard
will use C99 as the reference, rather than C90; in C99,
infinity is required to be output as either "inf" or "infinity",
and both should convert to infinity when read.

The current standard does not allow this behavior, however, nor
does the current draft, since they do not allow extraction of
"inf" when reading a number. So while the implementations I
usually use all output "inf", all report a read error when
attempting to read it back into a double. The only solution I
know of off hand is to read into a string, compare manually for
inf and nan, and use istringstream to convert the double if thos
tests fail.
 
P

Pete Becker

std::eek:fstream outf("test.txt");
if ( outf.is_open() )
outf << Infinity;

outf.close();

There's no newline at the end of "test.txt", so technically it's not a
valid text stream. No guarantees, but adding a newline might help.
 
J

Jim Langston

The output of the following program is:
1.#INF
1

was expected and desired. How can I read a value of infinity
from a stream?

According to the current C++ standard, there is no infinity, so
you're in the realm of implementation defined, if not undefined
behavior. Presumably, however, the next version of the standard
will use C99 as the reference, rather than C90; in C99,
infinity is required to be output as either "inf" or "infinity",
and both should convert to infinity when read.

The current standard does not allow this behavior, however, nor
does the current draft, since they do not allow extraction of
"inf" when reading a number. So while the implementations I
usually use all output "inf", all report a read error when
attempting to read it back into a double. The only solution I
know of off hand is to read into a string, compare manually for
inf and nan, and use istringstream to convert the double if thos
tests fail.

---------------

Hmmm.. I was actually looking for a 9's rule number to indicate no value.
But it seems that infinity won't do it for me then, especially since I need
to read 3 of these values in a row.

I guess can I can research an ifstream implementation to read 1.#INF as
infinity, create my own class and override operator<<. It might be enough
in this specific implementation to read the number, if it's 1, peek at the
next value, if it's # then presume it's going to be #INF, read to string,
compare for #INF and if so load infinity. And then override operator float.

Let me see what I can come up with.
 
J

Jim Langston

[Snip discussion about C++ not supporing infinity]

Well, this is what I came up with. Output is as I want. Do you see
anything I'm doing wrong here? Of course I'll have to come up with a better
name than "MyFloat".

1.#INF
1 2.2 3.3
1.#INF 2.2 3.3

#include <iostream>
#include <fstream>
#include <limits>
#include <string>

class MyFloat
{
public:
MyFloat( float Value = 0.0f ): Value( Value ) {}
operator float() { return Value; }
float Value;
};

std::istream& operator>>( std::istream& is, MyFloat& mf )
{
if ( is >> mf.Value )
{
if ( mf.Value == 1.0f && is.peek() == '#' )
{
std::string Rest;
is >> Rest;
if ( Rest == "#INF" )
mf.Value = std::numeric_limits<float>::infinity();
}
}

return is;
}

int main(void)
{
float Infinity, Foo = 2.2f, Bar = 3.3f;
Infinity = std::numeric_limits<float>::infinity();
std::cout << Infinity << "\n";

std::eek:fstream outf("test.txt");
if ( outf.is_open() )
outf << Infinity << " " << Foo << " " << Bar << "\n";

outf.close();

float Value = 0.0f, Value2 = 0.0f, Value3 = 0.0f;
std::ifstream inf("test.txt");
if ( inf.is_open() )
inf >> Value >> Foo >> Bar;

inf.close();

std::cout << Value << " " << Foo << " " << Bar << "\n";

MyFloat MyValue = 0.0f, MyValue2 = 0.0f, MyValue3 = 0.0f;
std::ifstream inf2("test.txt");
if ( inf2.is_open() )
inf2 >> MyValue >> MyValue2 >> MyValue3;

inf2.close();

std::cout << MyValue << " " << MyValue2 << " " << MyValue3 << "\n";

return 0;
}
 
J

Jim Langston

Jim Langston said:
[Snip discussion about C++ not supporing infinity]

Well, this is what I think I'll put into production, unless anyone can show
me any flaws in it. It seems to work fine as a float in my rudimentary
tests.

namespace jml
{
class Float
{
public:
Float( float Value = 0.0f ): Value( Value ) {}
operator float() { return Value; }
float Value;
};

std::istream& operator>>( std::istream& is, Float& mf )
{
if ( is >> mf.Value )
{
if ( mf.Value == 1.0f && is.peek() == '#' )
{
std::string Rest;
is >> Rest;
if ( Rest == "#INF" )
mf.Value = std::numeric_limits<float>::infinity();
}
}

return is;
}

};

I'll probably make Value private just because.
 
V

Victor Bazarov

Jim said:
[..]
Well, this is what I think I'll put into production, unless anyone
can show me any flaws in it. It seems to work fine as a float in my
rudimentary tests.

namespace jml
{
class Float
{
public:
Float( float Value = 0.0f ): Value( Value ) {}
operator float() { return Value; }
float Value;
};

std::istream& operator>>( std::istream& is, Float& mf )
{
if ( is >> mf.Value )
{
if ( mf.Value == 1.0f && is.peek() == '#' )
{
std::string Rest;
is >> Rest;
if ( Rest == "#INF" )
mf.Value = std::numeric_limits<float>::infinity();
}
}

return is;
}

};

I'll probably make Value private just because.

Actually, I'd probably get rid of 'operator float()' in it (besides,
it ought to be declared 'const' if you ask me), and always use the
explicit ".Value", or have a function called "value()" in it instead:

class Float
{
...
float value() const { return Value; }
private:
float Value;
};

Recently in our development we ran into some implicit conversions
that we didn't want, and it was all due to type conversion functions
(which BTW you can't declare "explicit"). We decided we didn't like
those in our own types.

V
 
J

James Kanze

"Jim Langston" <[email protected]> wrote in message
"James Kanze"
[Snip discussion about C++ not supporing infinity]
Well, this is what I came up with. Output is as I want. Do
you see anything I'm doing wrong here? Of course I'll have to
come up with a better name than "MyFloat".
1.#INF
1 2.2 3.3
1.#INF 2.2 3.3
#include <iostream>
#include <fstream>
#include <limits>
#include <string>
class MyFloat
{
public:
MyFloat( float Value = 0.0f ): Value( Value ) {}
operator float() { return Value; }
float Value;
};
std::istream& operator>>( std::istream& is, MyFloat& mf )
{
if ( is >> mf.Value )
{
if ( mf.Value == 1.0f && is.peek() == '#' )
{
std::string Rest;
is >> Rest;
if ( Rest == "#INF" )
mf.Value = std::numeric_limits<float>::infinity();
}
}
return is;
}

I'm not sure I like that. You've built in knowledge of how your
implementation formats infinity, and I'll bet that this format
is not guaranteed. I'd do something more along the lines of:

std::istream&
operator>>( std::istream& in, MyFloat& out )
{
std::string s ;
in >> s ;
if ( in ) {
static std::string const
infRepresentation =
initInfRepresentation() ;
if ( s == infRepresentation ) {
out.value = std::numeric_limits< float >::infinity() ;
} else {
std::istringstream t( s ) ;
t >> out.value ;
}
}
return in ;
}

with:

std::string
initInfRepresentation()
{
std::eek:stringstream t ;
t << std::numeric_limits< float >::infinity() ;
return t.string() ;
}

Actually, I'd go even further, since I'd want to handle at
least positive and negative infinity, and I'd probably make the
comparison case insensitive. But you get the idea.

And of course, regardless of the solution, you have to be aware
that it will break anytime the compiler changes its
representation of infinity. Which in your case seems almost
inevitable, given that the C99 standard requires "[+-]inf" or
"[+-]infinity", and that this requirement will almost certainly
be part of the next version of the C++ standard. So if you want
any kind of portability, you really have to use your MyFloat for
both output and input.
 
J

Jim Langston

James Kanze said:
"Jim Langston" <[email protected]> wrote in message
"James Kanze"
The output of the following program is:
1.#INF
1
But:
1.#INF
1.#INF
was expected and desired. How can I read a value of infinity
from a stream?
[Snip discussion about C++ not supporing infinity]

Well, this is what I came up with. Output is as I want. Do
you see anything I'm doing wrong here? Of course I'll have to
come up with a better name than "MyFloat".
1.#INF
1 2.2 3.3
1.#INF 2.2 3.3
#include <iostream>
#include <fstream>
#include <limits>
#include <string>
class MyFloat
{
public:
MyFloat( float Value = 0.0f ): Value( Value ) {}
operator float() { return Value; }
float Value;
};
std::istream& operator>>( std::istream& is, MyFloat& mf )
{
if ( is >> mf.Value )
{
if ( mf.Value == 1.0f && is.peek() == '#' )
{
std::string Rest;
is >> Rest;
if ( Rest == "#INF" )
mf.Value = std::numeric_limits<float>::infinity();
}
}
return is;
}

I'm not sure I like that. You've built in knowledge of how your
implementation formats infinity, and I'll bet that this format
is not guaranteed. I'd do something more along the lines of:

std::istream&
operator>>( std::istream& in, MyFloat& out )
{
std::string s ;
in >> s ;

One thing here, though, is you read a string from istream. This could put
is in a different state then if this operator>> wasn't used. For example.
Say what is waiting is:
123.45And that's all.

Using a pure is >> float
"And that's all" would be waiting in the stream. With this function this
way, however, "And that's all" will be thrown away.

The way I did it it would only be thrown away if the first character was #,
not as likely an occurance (but adminttedly still could happen).

Other than that, I agree with your assessment. But I don't like putting the
stream in a state that would be different if my function wasn't used.
if ( in ) {
static std::string const
infRepresentation =
initInfRepresentation() ;
if ( s == infRepresentation ) {
out.value = std::numeric_limits< float >::infinity() ;
} else {
std::istringstream t( s ) ;
t >> out.value ;
}
}
return in ;
}

with:

std::string
initInfRepresentation()
{
std::eek:stringstream t ;
t << std::numeric_limits< float >::infinity() ;
return t.string() ;
}

Actually, I'd go even further, since I'd want to handle at
least positive and negative infinity, and I'd probably make the
comparison case insensitive. But you get the idea.

And of course, regardless of the solution, you have to be aware
that it will break anytime the compiler changes its
representation of infinity. Which in your case seems almost
inevitable, given that the C99 standard requires "[+-]inf" or
"[+-]infinity", and that this requirement will almost certainly
be part of the next version of the C++ standard. So if you want
any kind of portability, you really have to use your MyFloat for
both output and input.
 
J

Jim Langston

Jim Langston said:
"Jim Langston" <[email protected]> wrote in message
"James Kanze"
The output of the following program is:
1.#INF
1
But:
1.#INF
1.#INF

was expected and desired. How can I read a value of infinity
from a stream?

[Snip discussion about C++ not supporing infinity]

Well, this is what I came up with. Output is as I want. Do
you see anything I'm doing wrong here? Of course I'll have to
come up with a better name than "MyFloat".
1.#INF
1 2.2 3.3
1.#INF 2.2 3.3
#include <iostream>
#include <fstream>
#include <limits>
#include <string>
class MyFloat
{
public:
MyFloat( float Value = 0.0f ): Value( Value ) {}
operator float() { return Value; }
float Value;
};
std::istream& operator>>( std::istream& is, MyFloat& mf )
{
if ( is >> mf.Value )
{
if ( mf.Value == 1.0f && is.peek() == '#' )
{
std::string Rest;
is >> Rest;
if ( Rest == "#INF" )
mf.Value = std::numeric_limits<float>::infinity();
}
}
return is;
}

I'm not sure I like that. You've built in knowledge of how your
implementation formats infinity, and I'll bet that this format
is not guaranteed. I'd do something more along the lines of:

std::istream&
operator>>( std::istream& in, MyFloat& out )
{
std::string s ;
in >> s ;

One thing here, though, is you read a string from istream. This could put
is in a different state then if this operator>> wasn't used. For example.
Say what is waiting is:
123.45And that's all.

Using a pure is >> float
"And that's all" would be waiting in the stream. With this function this
way, however, "And that's all" will be thrown away.

Actually, "And" would be thrown away.
The way I did it it would only be thrown away if the first character was
#, not as likely an occurance (but adminttedly still could happen).

Other than that, I agree with your assessment. But I don't like putting
the stream in a state that would be different if my function wasn't used.
if ( in ) {
static std::string const
infRepresentation =
initInfRepresentation() ;
if ( s == infRepresentation ) {
out.value = std::numeric_limits< float >::infinity() ;
} else {
std::istringstream t( s ) ;
t >> out.value ;
}
}
return in ;
}

with:

std::string
initInfRepresentation()
{
std::eek:stringstream t ;
t << std::numeric_limits< float >::infinity() ;
return t.string() ;
}

Actually, I'd go even further, since I'd want to handle at
least positive and negative infinity, and I'd probably make the
comparison case insensitive. But you get the idea.

And of course, regardless of the solution, you have to be aware
that it will break anytime the compiler changes its
representation of infinity. Which in your case seems almost
inevitable, given that the C99 standard requires "[+-]inf" or
"[+-]infinity", and that this requirement will almost certainly
be part of the next version of the C++ standard. So if you want
any kind of portability, you really have to use your MyFloat for
both output and input.
 
J

James Kanze

[...]
One thing here, though, is you read a string from istream. This could put
is in a different state then if this operator>> wasn't used. For example.
Say what is waiting is:
123.45And that's all.
Using a pure is >> float
"And that's all" would be waiting in the stream. With this function this
way, however, "And that's all" will be thrown away.

Just the "And". And I know. I don't like it, but...

I'm not really sure what the C standard says here---C99
requires, for example, that the string "Infinity" be recognized
and read as a valid float or double, e.g. when matching a "%f"
or "%lf" in a scanf. What happens when it tries to match
"Infinitx" to a "%f". I don't see any way that it could be made
to work so that you don't extract some characters which aren't
then consumed as part of a value. (Remember that "Inf" *is*
also a legitimate float/double value in C. So given the above,
and a scanf format like "%f%s", the float should contain
infinity, and the string "initx". And of course, only one
character push back/look ahead is allowed.) I think that
there's a fundamental problem involved, without any real
solution.

My own very personal opinion on the matter is that the only real
solution is to specify that for formatted input, the stream is
considered to consist of a series of "words", separated by white
space, that all >> operators consume an entire word, and that
that word must conform to the target format. In other words,
something like your example would result in a format error when
reading the floating point value, since "123.45And" is not a
valid floating point value. The standard cannot adopt this
point of view, however, since it would break existing code.

In the meantime, if this does bother you, it's not too difficult
to compile a (pure) regular expression to a DFA, and use it
while reading. The RegularExpression class at my site is
designed to support this (which is why it doesn't support any of
the common extensions to regular expressions, either). The
RegularExpression class at my site will also work with
InputIterators; you can call its match() function with
istreambuffer_iterator<char>, for example. (But you'd have to
wrap it so that it would copy the characters into a stream as
they are seen, so that you could convert them once you've found
the match.) But you'd still have the problem that with
"Infinitx", the match will be for "Inf", but "Infinitx" will
have been extracted from the stream. Which means that you've
specified a functionality which cannot be met in a very few,
specific cases.
The way I did it it would only be thrown away if the first
character was #, not as likely an occurance (but adminttedly
still could happen).
Other than that, I agree with your assessment. But I don't
like putting the stream in a state that would be different if
my function wasn't used.

But as you say, "admittedly still could happen". (I guess I'm a
little bit of a perfectionist.)

Note that if you're using wide streams, you could implement your
own extraction and insertion operators, using \u221E for
infinity; since it is a single character, and you have one
character look-ahead, you could handle it more or less
correctly.

But IMHO, the problem is already present, in the current
specifications. What about a sequence like "1.23E-x"? I'm at
home right now, and don't have access to a variety of compilers,
but I seem to remember having played around with this, and found
that different compilers do different things. According to the
standard "1.23E-" is extracted from the stream. Beyond that,
I'm less sure (even with the standard in front of my eyes):
should it then result in an error (setting ios::failbit), or
1.23, with no error. (The first seems more logical to me, but
the second seems closer to what the standard seems to say.)

In sum, there are no easy solutions (or no correct solution, for
an adequately rigorous definition of "correct"). But I would
definitly recommend that you implement both insertion and
extraction, and use either "inf" or "infinity" as the string (in
whatever case you wish), this being what the C99 standard
requires, and thus presumably what the next version of the C++
standard will require.
 
B

Ben Pfaff

James Kanze said:
I'm not really sure what the C standard says here---C99
requires, for example, that the string "Infinity" be recognized
and read as a valid float or double, e.g. when matching a "%f"
or "%lf" in a scanf. What happens when it tries to match
"Infinitx" to a "%f". I don't see any way that it could be made
to work so that you don't extract some characters which aren't
then consumed as part of a value. (Remember that "Inf" *is*
also a legitimate float/double value in C. So given the above,
and a scanf format like "%f%s", the float should contain
infinity, and the string "initx". And of course, only one
character push back/look ahead is allowed.) I think that
there's a fundamental problem involved, without any real
solution.

C99 clarified the behavior of fscanf, with the following sentence
and footnote:

An input item is defined as the longest sequence of input
characters which does not exceed any specified field width
and which is, or is a prefix of, a matching input
sequence.242)

242) fscanf pushes back at most one input character onto the
input stream. Therefore, some sequences that are
acceptable to strtod, strtol, etc., are unacceptable to
fscanf.
 
J

Jim Langston

Ben Pfaff said:
C99 clarified the behavior of fscanf, with the following sentence
and footnote:

An input item is defined as the longest sequence of input
characters which does not exceed any specified field width
and which is, or is a prefix of, a matching input
sequence.242)

242) fscanf pushes back at most one input character onto the
input stream. Therefore, some sequences that are
acceptable to strtod, strtol, etc., are unacceptable to
fscanf.

If the standard says that (and you say it does, so I don't doubt it) then I
have no problem with Jame's solution. If the standard disallows some
sequences as unacceptable then I think that using Infinity and leaving the
stream in some undefined state is acceptable (undefined as to how different
compilers may do it when C++Ox comes out).
 
J

James Kanze

C99 clarified the behavior of fscanf, with the following sentence
and footnote:
An input item is defined as the longest sequence of input
characters which does not exceed any specified field width
and which is, or is a prefix of, a matching input
sequence.242)
242) fscanf pushes back at most one input character onto the
input stream. Therefore, some sequences that are
acceptable to strtod, strtol, etc., are unacceptable to
fscanf.

I'm not too sure about the footnote (which is non-normative),
but if I understand the phrase correctly, given

sscanf( "Infinitx", "%f%s", &aFloat, aCharBuffer ) ;

the library would put infinity in aFloat, and "x" in
aCharBuffer.

As I said, it's not an easy problem, and there's no good
solution. About the only way to handle this sort of thing
correctly is to read a complete line, then use regular
expressions to match what looks like a floating point, i.e.
something like
"[+-](" "([0-9]+\.[0-9]*([Ee][+-]?[0-9]+)?)"
"|(\.[0-9]+([Ee][+-]?[0-9]+)?)"
"|([0-9]+[Ee][+-]?[0-9]+)"
"|([Ii][Nn][Ff])"
"|([Ii][Nn][Ff][Ii][Nn][Ii][Tt][Yy])"
")"
(The exact syntax will depend on the regular expression class
you use. The above corresponds to my own regular expression
class---which is probably not the one you use, or even should be
using.)

Any reasonable regular expression class will allow you to obtain
the end point of the match; you then use that and the starting
point to create a string which initializes an istringsream,
which then converts the input. This works, of course, only
because you can easily multiply scan in a string; the look-ahead
needed when matching Infinitx, for example, doesn't matter,
because when you do the actual conversion, you'll reread from
the start anyway, and only read the characters which were really
part of the match.

Note that for a seekable input source, you can do this with my
RegularExpression class (which itself works with input
iterators, although there's not often much you can do with the
output in such cases) as well: memorize the current position,
break up the different cases above, try for the match each time,
reseeking to the original position in case of failure; for
either "inf" or "infinity", just store the results; for anything
else, >> into a double&.
 
B

Ben Pfaff

James Kanze said:
I'm not too sure about the footnote (which is non-normative),
but if I understand the phrase correctly, given

sscanf( "Infinitx", "%f%s", &aFloat, aCharBuffer ) ;

the library would put infinity in aFloat, and "x" in
aCharBuffer.

I interpreted this the opposite way: that the library's attempt
to match "Infinity" would fail at 'x' and therefore push back 'x'
and return 0, having consumed "Infinit".

Not that it matters much.
 
J

James Kanze

I interpreted this the opposite way: that the library's attempt
to match "Infinity" would fail at 'x' and therefore push back 'x'
and return 0, having consumed "Infinit".

This is the point where I'm not sure. From the above phrase, it
seems clear that the "%f" specifier would consume "Infinit".
The question is then whether this sequence is an error. There
is a statement (§7.19.6.2/10): "If the input item is not a
matching sequence, the execution of the directive fails: this
condition is a matching failure." But what does it really mean
by "matching sequence"; for "%f", all it says is: "Matches an
optionally signed floating-point number, infinity, or NaN whose
format is the same as expected for the subject sequence of the
strtod function." The strtod function accepts "Infinit" without
problems.

But you're probably right, since in the description of stdtod,
the term "subject sequence" is also used, and given "Infinit" as
input, the "subject sequence" for stdtod is "Inf", which is not
the sequence which was extracted.

This would solve Jim Langston's problem nicely. In his
conversion operator, having gotten past any leading white space
and the sign, he can then do a switch on the next character:
[0-9.], and the usual floating point conversion can be used
(he's already extracted the sign, but that's easy to handle
after the conversion); [Ii], and he advances, extracting the
characters, trying to match "infinity"---if the resulting string
matches "inf" or "infinity", that's the results, otherwise, it's
an error; and for [Nn], he does the same thing for "nan" (not
forgetting the n-char-sequence, if he wants to be strictly
conform with C---but then, he also has to handle the hex
format, since his C++ implementation almost certainly won't).

Just for the fun of it, I whipped up a simple implementation
here. It doesn't handle all of the formatting flags correctly,
and it supposes a C99 compliant math.h, but it should be a good
starting point:

class FloatWithInfIn
{
public:
FloatWithInfIn( float& f )
: myValue( &f )
{
}

friend std::eek:stream&operator<<( std::eek:stream& dest,
FloatWithInfIn const& src ) ;
friend std::istream&operator>>( std::istream& source,
FloatWithInfIn const& dest ) ;

private:
float* myValue ;
} ;

class FloatWithInfOut
{
public:
FloatWithInfOut( float const& f )
: myValue( &f )
{
}

friend std::eek:stream&operator<<( std::eek:stream& dest,
FloatWithInfOut const& src ) ;

private:
float const* myValue ;
} ;

std::eek:stream&
outputFloatWithInf(
std::eek:stream& dest,
float const& value )
{
switch ( fpclassify( value ) ) {
case FP_INFINITE :
if ( value < 0.0 ) {
dest << '-' ;
} else if ( (dest.flags() & std::ios::showpos) != 0 ) {
dest << '+' ;
}
dest << "Infinity" ;
break ;

case FP_NAN :
dest << "NaN" ;
break ;

default :
dest << value ;
break ;
}
return dest ;
}

inline std::eek:stream&
operator<<(
std::eek:stream& dest,
FloatWithInfOut const&
value )
{
return outputFloatWithInf( dest, *value.myValue ) ;
}

inline std::eek:stream&
operator<<(
std::eek:stream& dest,
FloatWithInfIn const&
value )
{
return outputFloatWithInf( dest, *value.myValue ) ;
}

void
getInfinity(
std::istream& source,
float& dest )
{
static std::string const
inf( "infinity" ) ;
std::ctype< char > const&
ctype
= std::use_facet said:
( source.getloc() ) ;
std::string extracted ;
std::string::const_iterator
pos = inf.begin() ;
while ( pos != inf.end() && ctype.tolower( source.peek() ) ==
*pos ) {
extracted += ctype.tolower( source.get() ) ;
++ pos ;
}
if ( extracted != "inf" && extracted != "infinity" ) {
source.setstate( std::ios::failbit ) ;
} else {
dest = std::numeric_limits< float >::infinity() ;
}
}

void
getNaN(
std::istream& source,
float& dest )
{
static std::string const
nan( "nan" ) ;
std::ctype< char > const&
ctype
= std::use_facet said:
( source.getloc() ) ;
std::string extracted ;
std::string::const_iterator
pos = nan.begin() ;
while ( pos != nan.end() && ctype.tolower( source.peek() ) ==
*pos ) {
extracted += ctype.tolower( source.get() ) ;
++ pos ;
}
if ( extracted != "nan" ) {
source.setstate( std::ios::failbit ) ;
} else {
// Or maybe only characters in the basic character set
// should be allowed here.
while ( ctype.is( std::ctype_base::alnum, source.peek() )
|| source.peek() == '_' ) {
source.get() ;
}
dest = std::numeric_limits< float >::quiet_NaN() ;
}
}

std::istream&
operator>>(
std::istream& source,
FloatWithInfIn const&
dest )
{
if ( (source.flags() & std::ios::skipws) != 0 ) {
source >> std::ws ;
}
char sign
= ( source.peek() == '-' || source.peek() == '+'
? source.get()
: '+' ) ;
float result = 0.0 ;
switch ( source.peek() ) {
case 'I' :
case 'i' :
getInfinity( source, result ) ;
break ;

case 'N' :
case 'n' :
getNaN( source, result ) ;
break ;

default :
{
// Should use RAII for this, since >> can throw...
std::ios::fmtflags flags = source.flags() ;
source.unsetf( std::ios::skipws ) ;
source >> result ;
source.flags( flags ) ;
}
break ;
}
if ( source ) {
*dest.myValue = ( sign == '-'
? - result
: result ) ;
}
return source ;
}

FloatWithInfIn
floatWithInf(
float& f )
{
return FloatWithInfIn( f ) ;
}

FloatWithInfOut
floatWithInf(
float const& f )
{
return FloatWithInfOut( f ) ;
}

(Note the use of a function to automatically choose, according
to lvalue-ness and const-ness, whether we can do just output, or
both.)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top