Discussion:
"nan".to_f ?
Thomas Fini Hansen
2004-10-12 09:14:49 UTC
Permalink
I ran into this difference:

---
irb(main):001:0> VERSION
"1.6.7"
irb(main):002:0> "nan".to_f
NaN
---
irb(main):001:0> VERSION
=> "1.8.2"
irb(main):002:0> "nan".to_f
=> 0.0
---

(1.8.2 is really 1.8.1+1.8.2pre2-1woody1 in Debian)

I wouldn't have been surprised if it was the other way round. Can
anyone explain why it is so? Seemed like a nice feature to me.
--
Thomas
***@system-tnt.dk
Robo
2004-10-12 09:34:36 UTC
Permalink
Post by Thomas Fini Hansen
---
irb(main):001:0> VERSION
"1.6.7"
irb(main):002:0> "nan".to_f
NaN
---
irb(main):001:0> VERSION
=> "1.8.2"
irb(main):002:0> "nan".to_f
=> 0.0
---
(1.8.2 is really 1.8.1+1.8.2pre2-1woody1 in Debian)
I wouldn't have been surprised if it was the other way round. Can
anyone explain why it is so? Seemed like a nice feature to me.
Why would Ruby turn "nan" to "NaN" when you told it to convert the
string to a float? I don't see the connection.

Robo
gabriele renzi
2004-10-12 09:39:36 UTC
Permalink
Post by Robo
Why would Ruby turn "nan" to "NaN" when you told it to convert the
string to a float? I don't see the connection.
NaN stands for Not a Number and is a 'builtin' value in floating point
math system (I mean, at the cpu level)
Stephan Kämper
2004-10-12 09:39:36 UTC
Permalink
Hi Thomas, hi Rubyists
Post by Thomas Fini Hansen
---
irb(main):001:0> VERSION
"1.6.7"
irb(main):002:0> "nan".to_f
NaN
---
irb(main):001:0> VERSION
=> "1.8.2"
irb(main):002:0> "nan".to_f
=> 0.0
---
(1.8.2 is really 1.8.1+1.8.2pre2-1woody1 in Debian)
I wouldn't have been surprised if it was the other way round. Can
anyone explain why it is so? Seemed like a nice feature to me.
ri String#to_f
------------------------------------------------------------ String#to_f
str.to_f => float
------------------------------------------------------------------------
Returns the result of interpreting leading characters in _str_ as a
floating point number. Extraneous characters past the end of a
valid number are ignored. If there is not a valid number at the
start of _str_, +0.0+ is returned. This method never raises an
exception.

"123.45e1".to_f #=> 1234.5

"45.67 degrees".to_f #=> 45.67

"thx1138".to_f #=> 0.0

I don't use String#to_f a lot, because I'd prefer Float( a_string ).
Float() is stricter and raises an ArgumentError if the whole String
can't be interpreted as a Float, while String#to_s tries to create a
Float from the first characters and stops when/if there are any chars
that wouldn't yield a Float.

Happy rubying

Stephan
Markus
2004-10-12 16:14:30 UTC
Permalink
Yes, but his point is that "NaN" _is_ the string representation of
valid floating point value, defined and handled by the system, with
standardized semantics, etc.
"NaN".to_f should return NaN. How else are you going to reliably
get NaN if you need it?
IMO, this is a bug.

-- Markus
Post by Stephan Kämper
Hi Thomas, hi Rubyists
Post by Thomas Fini Hansen
---
irb(main):001:0> VERSION
"1.6.7"
irb(main):002:0> "nan".to_f
NaN
---
irb(main):001:0> VERSION
=> "1.8.2"
irb(main):002:0> "nan".to_f
=> 0.0
---
(1.8.2 is really 1.8.1+1.8.2pre2-1woody1 in Debian)
I wouldn't have been surprised if it was the other way round. Can
anyone explain why it is so? Seemed like a nice feature to me.
ri String#to_f
------------------------------------------------------------ String#to_f
str.to_f => float
------------------------------------------------------------------------
Returns the result of interpreting leading characters in _str_ as a
floating point number. Extraneous characters past the end of a
valid number are ignored. If there is not a valid number at the
start of _str_, +0.0+ is returned. This method never raises an
exception.
"123.45e1".to_f #=> 1234.5
"45.67 degrees".to_f #=> 45.67
"thx1138".to_f #=> 0.0
I don't use String#to_f a lot, because I'd prefer Float( a_string ).
Float() is stricter and raises an ArgumentError if the whole String
can't be interpreted as a Float, while String#to_s tries to create a
Float from the first characters and stops when/if there are any chars
that wouldn't yield a Float.
Happy rubying
Stephan
Mikael Brockman
2004-10-12 16:22:07 UTC
Permalink
Post by Markus
Yes, but his point is that "NaN" _is_ the string representation of
valid floating point value, defined and handled by the system, with
standardized semantics, etc.
"NaN".to_f should return NaN. How else are you going to reliably
get NaN if you need it?
0.0/0.0? :-)
Stephan Kämper
2004-10-12 16:49:37 UTC
Permalink
Post by Mikael Brockman
Post by Markus
Yes, but his point is that "NaN" _is_ the string representation of
valid floating point value, defined and handled by the system, with
standardized semantics, etc.
"NaN".to_f should return NaN. How else are you going to reliably
get NaN if you need it?
When would you *need* NaN in the first place? To show the the result of
some calculation is NaN? The just return that calculation.

To test whether something is NaN? -> There's Float#nan? to do that.
Post by Mikael Brockman
0.0/0.0? :-)
Happy rubying

Stephan
Markus
2004-10-12 17:20:04 UTC
Permalink
Post by Stephan Kämper
When would you *need* NaN in the first place? To show the the result of
some calculation is NaN? The just return that calculation.
I don't have a specific example in mind. Perhaps you're writing
something that evaluates a parameterized infinite series and want to
return NaN in the case where it doesn't converge (this being
significantly faster than an infinite loop). Who knows?

There may be other, better examples, but the point is _someone_ has
to be able to generate NaN, at some level (else we'd never see it) and
so it is at least plausible that that someone might be one of us.
Post by Stephan Kämper
To test whether something is NaN? -> There's Float#nan? to do that.
Good point.

-- Markus
Markus
2004-10-13 12:18:38 UTC
Permalink
Post by Yukihiro Matsumoto
|I would say that 'NaN' is a the string representation of a float, so
|logically it should be parsed to such, that's why I'm wondering why
|this behaviour was *removed*.
It's not valid string representation of a float.
Then why does:

x = 0.0/0.0
x.class #Float
x.to_s #NaN

If "NaN" is not the valid string representation of a Float, why
does calling Float#to_s return it?
Post by Yukihiro Matsumoto
Ruby used to use system's strtod(3), which gives you "nan" an
"inf" for free, but its interpretation varies a little from platform
to platform. Now it uses its own version of strtod that interprets
only valid float representation in Ruby.
The problem with this (in addition to some of my other contrived
examples, e.g. the non-convergent infinite series) is that we may want
to convert values to text and back (e.g., making XML) and would like to
be able to get something resembling the original values back.
Admittedly, it would be possible for users who wanted this to do it
themselves, but the performance consequences could be considerable.

-- Markus
Yukihiro Matsumoto
2004-10-13 12:38:22 UTC
Permalink
Hi,

In message "Re: "nan".to_f ?"
on Wed, 13 Oct 2004 21:18:38 +0900, Markus <***@reality.com> writes:

|> It's not valid string representation of a float.
|
| Then why does:
|
|x = 0.0/0.0
|x.class #Float
|x.to_s #NaN
|
| If "NaN" is not the valid string representation of a Float, why
|does calling Float#to_s return it?

Although we can tell whether a float value is NaN by using isnan(),
but as far as I know there's no portably way to generate NaN. I think
it's not guaranteed that 0.0/0.0 generate NaN.

If I'm wrong, feel free to correct me.

matz.
trans. (T. Onoma)
2004-10-13 13:45:01 UTC
Permalink
On Wednesday 13 October 2004 08:38 am, Yukihiro Matsumoto wrote:
| Hi,
|
| In message "Re: "nan".to_f ?"
|
| on Wed, 13 Oct 2004 21:18:38 +0900, Markus <***@reality.com> writes:
| |> It's not valid string representation of a float.
| |
| | Then why does:
| |
| |x = 0.0/0.0
| |x.class #Float
| |x.to_s #NaN
| |
| | If "NaN" is not the valid string representation of a Float, why
| |does calling Float#to_s return it?
|
| Although we can tell whether a float value is NaN by using isnan(),
| but as far as I know there's no portably way to generate NaN. I think
| it's not guaranteed that 0.0/0.0 generate NaN.

Not sure if portable, but one might try

(-1.0) ** 0.5

(Interesting also that '**' precedence is greater than '-'.)

T.
GOTO Kentaro
2004-10-13 14:33:53 UTC
Permalink
In message Re: "nan".to_f ?
Post by Yukihiro Matsumoto
Although we can tell whether a float value is NaN by using isnan(),
but as far as I know there's no portably way to generate NaN. I think
it's not guaranteed that 0.0/0.0 generate NaN.
def aNaN
s, e, m = rand(2), 2047, rand(2**52-1)+1
[sprintf("%1b%011b%052b", s,e,m)].pack("B*").unpack("G").first
end

I believe this will generate NaN on environments where
pack/unpack works and NaN exists.


Gotoken
Yukihiro Matsumoto
2004-10-13 17:39:43 UTC
Permalink
Hi,

In message "Re: "nan".to_f ?"
on Wed, 13 Oct 2004 23:33:53 +0900, GOTO Kentaro <***@notwork.org> writes:

| def aNaN
| s, e, m = rand(2), 2047, rand(2**52-1)+1
| [sprintf("%1b%011b%052b", s,e,m)].pack("B*").unpack("G").first
| end
|
|I believe this will generate NaN on environments where
|pack/unpack works and NaN exists.

If the platform uses IEEE floating number, right?

matz.
GOTO Kentaro
2004-10-14 16:44:04 UTC
Permalink
Hi,

In message "Re: "nan".to_f ?"
Post by Yukihiro Matsumoto
| def aNaN
| s, e, m = rand(2), 2047, rand(2**52-1)+1
| [sprintf("%1b%011b%052b", s,e,m)].pack("B*").unpack("G").first
| end
|
|I believe this will generate NaN on environments where
|pack/unpack works and NaN exists.
If the platform uses IEEE floating number, right?
Agreed! And if there exists NaN on a non IEEE platform,
that NaN must be another concept because NaN is defined in
IEEE 754.


Gotoken
Markus
2004-10-14 18:05:16 UTC
Permalink
My mistake is clear. I was assuming Float == IEEE.

I still see the original poster's desire to be able to serialize
floats as text without gross changes, but do not at this point see a
clear and portable way of implementing it. At best (using the code I
posted yesterday morning) you could maintain the distinction between
error-values and numbers, but this might well silently morph (say) Inf
to NaN, etc.

-- Markus
Post by Yukihiro Matsumoto
Hi,
In message "Re: "nan".to_f ?"
Post by Yukihiro Matsumoto
| def aNaN
| s, e, m = rand(2), 2047, rand(2**52-1)+1
| [sprintf("%1b%011b%052b", s,e,m)].pack("B*").unpack("G").first
| end
|
|I believe this will generate NaN on environments where
|pack/unpack works and NaN exists.
If the platform uses IEEE floating number, right?
Agreed! And if there exists NaN on a non IEEE platform,
that NaN must be another concept because NaN is defined in
IEEE 754.
Gotoken
GOTO Kentaro
2004-10-15 18:39:51 UTC
Permalink
In message Re: "nan".to_f ?
Post by Markus
My mistake is clear. I was assuming Float == IEEE.
Mistake? I don't think you mistook. or I also mistake.
When we are talking about Ruby, NaN means IEEE 754's NaN, isn't it? :)
Post by Markus
I still see the original poster's desire to be able to serialize
floats as text without gross changes, but do not at this point see a
clear and portable way of implementing it. At best (using the code I
posted yesterday morning) you could maintain the distinction between
error-values and numbers, but this might well silently morph (say) Inf
to NaN, etc.
NaN was designed to represent abnormal result of an arithmetic operation.
So, IMHO, String#to_f is not arithmetic and should not returns NaN.
By the way, we sometimes want to define a method return NaN value.
In such situations I believe pack/unpack will help.


Gotoken
Yukihiro Matsumoto
2004-10-15 18:44:14 UTC
Permalink
Hi,

In message "Re: "nan".to_f ?"
on Sat, 16 Oct 2004 03:39:51 +0900, GOTO Kentaro <***@notwork.org> writes:

|> My mistake is clear. I was assuming Float == IEEE.
|
|Mistake? I don't think you mistook. or I also mistake.
|When we are talking about Ruby, NaN means IEEE 754's NaN, isn't it? :)

C99 defines isnan() and isinf(). I'm not sure C99 assumes IEEE 754.

matz.
GOTO Kentaro
2004-10-15 19:02:31 UTC
Permalink
Hi,

In message Re: "nan".to_f ?
Post by Yukihiro Matsumoto
|When we are talking about Ruby, NaN means IEEE 754's NaN, isn't it? :)
C99 defines isnan() and isinf(). I'm not sure C99 assumes IEEE 754.
That is very IEEE 754 support.

ISO/IEC 9899:1999 Annex F says:

F.1 Introduction

This annex specifies C language support for the IEC 60559
floating-point standard. The IEC 60559 floating-point standard is
specifically Binary floating-point arithmetic for microprocessor
systems, second edition (IEC 60559:1989), previously designated IEC
559:1989 and as IEEE Standard for Binary Floating-Point Arithmetic
(ANSI/IEEE 754-1985). ...

Gotoken
Yukihiro Matsumoto
2004-10-16 02:48:06 UTC
Permalink
Hi,

In message "Re: "nan".to_f ?"
on Sat, 16 Oct 2004 04:02:31 +0900, GOTO Kentaro <***@notwork.org> writes:

|That is very IEEE 754 support.
|
|ISO/IEC 9899:1999 Annex F says:

<snip>

Does this mean that I can assume IEEE 754 on every platform?
If so, I'm glad that life is THAT simple.

matz.

Markus
2004-10-13 16:20:04 UTC
Permalink
Post by Yukihiro Matsumoto
Hi,
In message "Re: "nan".to_f ?"
|> It's not valid string representation of a float.
|
|
|x = 0.0/0.0
|x.class #Float
|x.to_s #NaN
|
| If "NaN" is not the valid string representation of a Float, why
|does calling Float#to_s return it?
Although we can tell whether a float value is NaN by using isnan(),
but as far as I know there's no portably way to generate NaN. I think
it's not guaranteed that 0.0/0.0 generate NaN.
If I'm wrong, feel free to correct me.
No, so far as I know you are correct (at as far as math operations
go). There was another sub-thread on this topic regarding the
assumption that 0.0/0.0 could be PosInf, NegInf, Inf, or NaN.

I believe there are defined binary representation of IEEE NaNs, so
one could be constructed. (See, for example

http://www.psc.edu/general/software/packages/ieee/ieee.html

), which I suspect is how the libs do it.

If we could count on 0.0/0.0 to always produce NaN, I believe the
original poster's goal could be met by writing something like:

class String
def to_i
Integer(self) rescue 0.0/0.0
end
end

...although this may not be as general as he needed.

-- Markus
Markus
2004-10-13 16:26:58 UTC
Permalink
Post by Stephan Kämper
class String
def to_f
Float(self) rescue 0.0/0.0
end
end
...I really shouldn't post before caffeination, esp. after being up half
the night chasing my son's imaginary tigers out of the house.

-- Markus
Post by Stephan Kämper
Post by Yukihiro Matsumoto
Hi,
In message "Re: "nan".to_f ?"
|> It's not valid string representation of a float.
|
|
|x = 0.0/0.0
|x.class #Float
|x.to_s #NaN
|
| If "NaN" is not the valid string representation of a Float, why
|does calling Float#to_s return it?
Although we can tell whether a float value is NaN by using isnan(),
but as far as I know there's no portably way to generate NaN. I think
it's not guaranteed that 0.0/0.0 generate NaN.
If I'm wrong, feel free to correct me.
No, so far as I know you are correct (at as far as math operations
go). There was another sub-thread on this topic regarding the
assumption that 0.0/0.0 could be PosInf, NegInf, Inf, or NaN.
I believe there are defined binary representation of IEEE NaNs, so
one could be constructed. (See, for example
http://www.psc.edu/general/software/packages/ieee/ieee.html
), which I suspect is how the libs do it.
If we could count on 0.0/0.0 to always produce NaN, I believe the
class String
def to_i
Integer(self) rescue 0.0/0.0
end
end
...although this may not be as general as he needed.
-- Markus
Stephan Kämper
2004-10-13 13:24:33 UTC
Permalink
Hi,
Post by Markus
The problem with this (in addition to some of my other contrived
examples, e.g. the non-convergent infinite series) is that we may want
to convert values to text and back (e.g., making XML) and would like to
be able to get something resembling the original values back.
Admittedly, it would be possible for users who wanted this to do it
themselves, but the performance consequences could be considerable.
-- Markus
I think there's not even a problem (or an SEP). You could easily

- Add NaN as a constant to class Float
- Implement String#to_f slightly bot not entirely different
so as to return NaN if the string begins with NaN

Something like this:

class Float
NaN = 0.0 / 0.0
end

class String
alias old_to_f to_f

def to_f
( self =~ /^nan/i ) ? Float::NaN : self.old_to_f
end
end

strings = [ "NaN1234", "nan", "nand is locical", "Nantucket? 70°07'W
41°18'N", "234234.234NaN", "1.0e23" ]

strings.each { | s |
puts "#{'%26s' % s} -> #{ s.to_f }"
}

Apparently this processing doesn't make sense for all Strings...


Happy rubying


Stephan
Thomas Fini Hansen
2004-10-12 20:22:00 UTC
Permalink
Post by Stephan Kämper
Post by Markus
Yes, but his point is that "NaN" _is_ the string representation of
valid floating point value, defined and handled by the system, with
standardized semantics, etc.
"NaN".to_f should return NaN. How else are you going to reliably
get NaN if you need it?
When would you *need* NaN in the first place? To show the the result of
some calculation is NaN? The just return that calculation.
Well, my case was pretty simple, I'm parsing the output of RRDTool,
which uses floats internally, and writes 'nan' for unknown data.
Post by Stephan Kämper
To test whether something is NaN? -> There's Float#nan? to do that.
Well, that was what I wanted to do, later, but now I have to check for
the string 'nan' at parse time, or else I'll get 0.0, when it's not
quite.

I would say that 'NaN' is a the string representation of a float, so
logically it should be parsed to such, that's why I'm wondering why
this behaviour was *removed*.

Not that it's an unsurmountable problem for what I'm doing, it's just
nicer and cleaner.
--
Thomas
***@system-tnt.dk
Yukihiro Matsumoto
2004-10-12 23:31:17 UTC
Permalink
Hi,

In message "Re: "nan".to_f ?"
on Wed, 13 Oct 2004 05:22:00 +0900, Thomas Fini Hansen <***@system-tnt.dk> writes:

|I would say that 'NaN' is a the string representation of a float, so
|logically it should be parsed to such, that's why I'm wondering why
|this behaviour was *removed*.

It's not valid string representation of a float.

ruby -e 'nan'
-e:1: undefined local variable or method `nan' for main:Object (NameError)

ruby -e 'NaN'
-e:1: uninitialized constant NaN (NameError)

Ruby used to use system's strtod(3), which gives you "nan" an "inf"
for free, but its interpretation varies a little from platform to
platform. Now it uses its own version of strtod that interprets only
valid float representation in Ruby.

matz.
Ryo Furue
2004-10-15 20:54:36 UTC
Permalink
Post by Yukihiro Matsumoto
Hi,
In message "Re: "nan".to_f ?"
|I would say that 'NaN' is a the string representation of a float, so
|logically it should be parsed to such, that's why I'm wondering why
|this behaviour was *removed*.
It's not valid string representation of a float.
[...]

Maybe I'm too late to jump in to this old thread
(three-days old is old enough for people to forget about
a thread :). Anyway, . . .

I think that symmetry is important, or if not important, it's nice
to have. So, *if*

x = 0.0/0.0 #=> NaN
x.to_s #=> "NaN"

*then*

y = "NaN".to_f # y *should* be NaN.

In other words, I'd expect (x.to_s).to_f to be an identity
operation (apart from potential truncation associated with to_s)
for a Float x.

I'm not saying that 0.0/0.0 *should* evaluate to NaN. That depends
on the platform. What I'm saying is that whatever x.to_s evaluates
to, (x.to_s).to_f "should" recover the (more-or-less) original value.
By "should", I mean "I wish".

Same goes for "Inf" and "-Inf".

Cheers,
Ryo
Yukihiro Matsumoto
2004-10-16 02:18:46 UTC
Permalink
Hi,

In message "Re: "nan".to_f ?"
on Sat, 16 Oct 2004 05:54:36 +0900, ***@ccsr.u-tokyo.ac.jp (Ryo Furue) writes:

| x = 0.0/0.0 #=> NaN
| x.to_s #=> "NaN"
|
|*then*
|
| y = "NaN".to_f # y *should* be NaN.

I agree that it's good to be so. The point is how I can implement
that in portable way. I'm waiting someone to enlighten me the way to
generate NaN portably, or that I can assume IEEE 754 for all the
platforms. Maybe Gotoken is saying the latter in [ruby-talk:116791],
but I'm not sure yet.

matz.
Markus
2004-10-12 17:07:52 UTC
Permalink
Post by Mikael Brockman
Post by Markus
Yes, but his point is that "NaN" _is_ the string representation of
valid floating point value, defined and handled by the system, with
standardized semantics, etc.
"NaN".to_f should return NaN. How else are you going to reliably
get NaN if you need it?
0.0/0.0? :-)
I almost went off on an IEEE spiel until I saw the ":-)"

-- Markus
Mikael Brockman
2004-10-12 17:15:52 UTC
Permalink
Post by Markus
Post by Mikael Brockman
Post by Markus
Yes, but his point is that "NaN" _is_ the string representation of
valid floating point value, defined and handled by the system, with
standardized semantics, etc.
"NaN".to_f should return NaN. How else are you going to reliably
get NaN if you need it?
0.0/0.0? :-)
I almost went off on an IEEE spiel until I saw the ":-)"
Actually, I'm as ignorant as you first assumed. Feel free to spiel if
you want. :-)
Markus
2004-10-12 17:33:19 UTC
Permalink
Post by Mikael Brockman
Post by Markus
Post by Mikael Brockman
Post by Markus
Yes, but his point is that "NaN" _is_ the string representation of
valid floating point value, defined and handled by the system, with
standardized semantics, etc.
"NaN".to_f should return NaN. How else are you going to reliably
get NaN if you need it?
0.0/0.0? :-)
I almost went off on an IEEE spiel until I saw the ":-)"
Actually, I'm as ignorant as you first assumed. Feel free to spiel if
you want. :-)
Short form: there are several NaN's, and "NaN like values" (e.g. +/-
infinity) and IIRC the form you gave could arguably return almost any of
them (except maybe -0.0).

-- Markus

http://www.freesoft.org/CIE/RFC/1832/32.htm
Warren Brown
2004-10-15 19:50:39 UTC
Permalink
Matz,
Post by Yukihiro Matsumoto
Although we can tell whether a float value is NaN by
using isnan(), but as far as I know there's no
portably way to generate NaN. I think it's not
guaranteed that 0.0/0.0 generate NaN.
If I'm wrong, feel free to correct me.
From what I can tell from Googling, the following operations are
*guaranteed* by IEEE Standard 754 to produce NaNs (where Inf = 1.0 /
0.0):

Inf - Inf
Inf * 0
0 / 0
Inf / Inf
x % 0
Inf % x
sqrt(x) (where x < 0)

One particularly authoritative document is at
http://grouper.ieee.org/groups/754. The first bullet near the bottom is
a link to David Goldberg's article "What Every Computer Scientist Should
Know about Floating-Point Arithmetic". Page 199 gives a table similar
to this one.

Of course, not every floating point package is IEEE Standard 754,
but these operations should produce NaNs regardless of the standard
used, since there are no other legal values available.

Do we know of any other floating-point standards that Ruby needs to
support?

- Warren Brown
Continue reading on narkive:
Loading...