Why doesn't Float() work the same as Integer()?

In my continuing work learning Ruby while creating a Rational class I ran into a problem with converting Strings. I am allowing Strings as input to the .new method and converting them to a Float, Integer, or Rational before continuing. At first I was just using Float(x) and later converting the Float to an Integer. This works fine unless I try something like Float("0x11") which crashes. Integer("0x11") returns 17 as expected. Currently I have to try to convert to Float and if that fails try to convert to Integer which seems to be more work than it needs to be.
If I use Float("17") it returns 17.0 and Float(0x11) returns 17.0, both as expected. Why doesn't Float("0x11") work? As Ruby doesn't appear to handle Floats of bases other than 10 (or at least I haven't figured out how to yet) I can see it choking on Float("0x11.34") but it shouldn't choke on Float("0x11").
Part of what I am doing is trying to follow the statement in Pickaxe about duck typing and programming for any input, not just a select subset.

If I use Float("17") it returns 17.0 and Float(0x11) returns 17.0, both as
expected.

Yes, because Kernel.Float knows how to convert string "17" to float
and number 17
written as 0x11 to float.

Why doesn't Float("0x11") work?

You answer that yourself. Unlike Kernel.Integer, Kernel.Float does not honor
radix indicators (0, 0b, 0x), thus string '0x11' is invalid for that method.
While '0x11'.to_f also does not know how to deal with this, it
silently returns 0.0.
Kernel.Float is different in that way, that it rises an exception when
given string is invalid.

As Ruby doesn't appear to handle
Floats of bases other than 10 (or at least I haven't figured out how to yet)
I can see it choking on Float("0x11.34") but it shouldn't choke on
Float("0x11").

It should. Because this method does not know anything about 0x prefix
the whole string is invalid
to it.
Kernel.Integer KNOWS how to deal with prefixes, so it handles ocatal,
binary and hex representations
in string format just fine.
<...>

Regards,
Rimantas

···

--
http://rimantas.com/

Michael W. Ryder wrote:

In my continuing work learning Ruby while creating a Rational class I
ran into a problem with converting Strings. I am allowing Strings as
input to the .new method and converting them to a Float, Integer, or
Rational before continuing. At first I was just using Float(x) and
later converting the Float to an Integer. This works fine unless I try
something like Float("0x11") which crashes. Integer("0x11") returns 17
as expected. Currently I have to try to convert to Float and if that
fails try to convert to Integer which seems to be more work than it
needs to be.
If I use Float("17") it returns 17.0 and Float(0x11) returns 17.0, both
as expected. Why doesn't Float("0x11") work? As Ruby doesn't appear to
handle Floats of bases other than 10 (or at least I haven't figured out
how to yet) I can see it choking on Float("0x11.34") but it shouldn't
choke on Float("0x11").
Part of what I am doing is trying to follow the statement in Pickaxe
about duck typing and programming for any input, not just a select
subset.

As someone who has done floating point validation on microprocessors, I
can unequivocally state that the only "alternate base" of interest is to
represent the byte string as nibbles or bits. That would be
'400000000000000000' => 2.0 in EP, '40000000000000000' => 2.0 in DP,
'400000000' => in SP. Which means of course that
'0000000040000000'.to_f != '40000000'.to_f. These are formats for IEEE
754. Note that the internal representation of extended precision
numbers has more bits. The Athlon had 91. Eariler cpus almost
certainly had at least 83. There are very, VERY few people working in
an environment where this matters, and most are good enough to write
their own code as needed.

The hex and binary options for specifying integers exist because we
often need to look at integers as bit strings. Oct is a historical
anomaly. Different classes have different behaviors because they are
different. The fact that Float and Int happen to share the base class
Numeric is of no concern to either.

···

--
Posted via http://www.ruby-forum.com/\.

Michael W. Ryder wrote:
[snip]

If I use Float("17") it returns 17.0 and Float(0x11) returns 17.0, both
as expected. Why doesn't Float("0x11") work? As Ruby doesn't appear to
handle Floats of bases other than 10 (or at least I haven't figured out
how to yet) I can see it choking on Float("0x11.34") but it shouldn't
choke on Float("0x11").

Actually, this is probably the most logical behavior. Integer() and
Float() have the same defined behavior; they both can accept one of two
inputs:
1. A Numeric that can be converted into the correct type;
2. A String that can be parsed into the correct type.

If a string is provided, then it must follow the same rules as the
appropriate literal representation.... This is the source of the
differences. So:

Integer("023") #=> 19
Float("023") #=> 23.0
Integer("0x23") #=> 35
Float("0x23") #=> ArgumentError!!!
Integer("1e3") #=> ArgumentError!!!
Float("1e3") #=> 1000.0

To make them truly cross-compatible would eliminate the error-checking.

Part of what I am doing is trying to follow the statement in Pickaxe
about duck typing and programming for any input, not just a select
subset.

Beware of doing *too much* duck typing. Figure out a reasonable point to
stop. Unless there's a significant amount of value added by allowing
strings, I wouldn't do it. If you can think of a reasonable circumstance
where the programmer would want to pass a string instead of an actual
number, go ahead; otherwise, it' just bloat, and bloat is a great source
for bugs :slight_smile:

···

--
Posted via http://www.ruby-forum.com/\.

Rimantas Liubertas wrote:

If I use Float("17") it returns 17.0 and Float(0x11) returns 17.0, both as
expected.

Yes, because Kernel.Float knows how to convert string "17" to float
and number 17
written as 0x11 to float.

Why doesn't Float("0x11") work?

You answer that yourself. Unlike Kernel.Integer, Kernel.Float does not honor
radix indicators (0, 0b, 0x), thus string '0x11' is invalid for that method.
While '0x11'.to_f also does not know how to deal with this, it
silently returns 0.0.
Kernel.Float is different in that way, that it rises an exception when
given string is invalid.

As Ruby doesn't appear to handle
Floats of bases other than 10 (or at least I haven't figured out how to yet)
I can see it choking on Float("0x11.34") but it shouldn't choke on
Float("0x11").

It should. Because this method does not know anything about 0x prefix
the whole string is invalid
to it.
Kernel.Integer KNOWS how to deal with prefixes, so it handles ocatal,
binary and hex representations
in string format just fine.
<...>

My question is why doesn't Float know how to deal with prefixes such as Hex? I wouldn't care if it tossed out invalid hex numbers such as 0x1h but it should at least try. As far as I am concerned the only difference between Float and Integer should be the return type, not what types they can handle. Integer has no problems with any valid Float or string representation of a Float, so Float should be able to handle any Integer or string representation of a valid Integer.
I could probably create a different version of Float or to_f for my class that handles string values like 0x11 but would rather not as it may confuse someone in the future if they didn't know that it was different than the built-in methods.

···

Regards,
Rimantas
--
http://rimantas.com/

Mark Hubbart wrote:

Michael W. Ryder wrote:
[snip]

If I use Float("17") it returns 17.0 and Float(0x11) returns 17.0, both
as expected. Why doesn't Float("0x11") work? As Ruby doesn't appear to
handle Floats of bases other than 10 (or at least I haven't figured out
how to yet) I can see it choking on Float("0x11.34") but it shouldn't
choke on Float("0x11").

Actually, this is probably the most logical behavior. Integer() and Float() have the same defined behavior; they both can accept one of two inputs:
1. A Numeric that can be converted into the correct type;
2. A String that can be parsed into the correct type.

If a string is provided, then it must follow the same rules as the appropriate literal representation.... This is the source of the differences. So:

Integer("023") #=> 19
Float("023") #=> 23.0
Integer("0x23") #=> 35
Float("0x23") #=> ArgumentError!!!
Integer("1e3") #=> ArgumentError!!!
Float("1e3") #=> 1000.0

To make them truly cross-compatible would eliminate the error-checking.

I am glad to see that I am not the only one that feels this way.

Part of what I am doing is trying to follow the statement in Pickaxe
about duck typing and programming for any input, not just a select subset.

Beware of doing *too much* duck typing. Figure out a reasonable point to stop. Unless there's a significant amount of value added by allowing strings, I wouldn't do it. If you can think of a reasonable circumstance where the programmer would want to pass a string instead of an actual number, go ahead; otherwise, it' just bloat, and bloat is a great source for bugs :slight_smile:

One of the nice things about Ruby is that a lot of the code necessary to cast a variable to another type is already there so for the most part it was very simple to add support for additional types of input. Along the way I learned about other things like handling exceptions, and hunting down some of the "bugs" in converting inputs is where I found some things that I feel are inconsistencies. Since this project is more for my benefit, as there already exists a rational module, I am not too worried about code bloat except when it occurs to handle unexpected behavior in the language.

Mark Hubbart wrote:

If a string is provided, then it must follow the same rules as the
appropriate literal representation.... This is the source of the

differences. So:
>> Integer("023") #=> 19
>> Float("023") #=> 23.0

But shouldn't Float("023") return an error in this case? After all "023" is
not a literal representation of a float (neither is "23").

···

--
Jabber: sepp2k@jabber.org
ICQ: 205544826

Well you're asking "why", and I suppose you'd have to address the
question to the core Ruby team. However, I can venture a guess, for
whatever that might be worth. And there are three elements to my
guess.

First, Float() and Integer() work like Ruby itself. In Ruby code you
can hardcode integer literals using 17 (dec), 021 (oct), or 0x11
(hex). But you can only hardcode floating point literals using base
ten. Admittedly, that's a bit of a punt since you'll probably ask why
Ruby works that way.

Second, I've never had the need to represent a floating point value as
a hexadecimal literal or string. With integers you sometimes need bit
masks and such. Perhaps there are domains where this would be very
useful. But I imagine most programmers don't typically run into
them. And like anything, people are more likely to do things that
they believe will be useful, or they scratch their own itches.

And my third reason is that there might be ambiguity in how to
interpret such a string. The representation of floating point values
as a bit pattern is typically done using IEEE 754. So, if we wanted
to represent a PI as a floating point double as a hexadecimal
constant, I think it would be "0x400921fb54442d18". However that
could also be interpreted as the integer 4,614,256,656,552,045,848.

Given your original post, you seem to be thinking that hexadecimal
constants would include a "." to separate the whole part from the
fractional part. In that case, I imagine pi would be represented as
"0x3.243f6a8885a3".

But for those programmers out there who'd want some type of
functionality, they may not be unified in their preference for the
format -- IEEE 754 or with an included decimal point.

I don't know how satisfying you'll find those answers, but they're the
best I can do.

By the way, if you want to include such functionality in your Rational
project, the following Ruby snippets might be helpful.

To figure out how pi would be represented as an IEEE 754 encoded
value, I used the following Ruby code:

    "0x" + [Math::PI].pack("G").unpack("H*").first

If you're unfamiliar with the methods, you may be interested in
reading the documentation on Array#pack and String#unpack.

To figure out how pi would be represented in the other form, I used
this Ruby code:

    fractional_hex_digits = 12 # how many hex digits right of decimal
    "0x" +
      Math::PI.floor.to_s(16) +
      "." +
      ((Math::PI - Math::PI.floor) *
         16**fractional_hex_digits).floor.to_s(16)

If you plan on using any of this code, please check my work since it
comes with absolutely to warranties.

Best,

Eric

···

On May 19, 7:44 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> wrote:

My question is why doesn't Float know how to deal with prefixes such as
Hex? I wouldn't care if it tossed out invalid hex numbers such as 0x1h
but it should at least try. As far as I am concerned the only
difference between Float and Integer should be the return type, not what
types they can handle.

====

LearnRuby.com offers Rails & Ruby HANDS-ON public & ON-SITE
workshops.
   Ruby Fundamentals Wkshp June 16-18 Ann Arbor, Mich.
   Ready for Rails Ruby Wkshp June 23-24 Ann Arbor, Mich.
   Ruby on Rails Wkshp June 25-27 Ann Arbor, Mich.
   Ruby Plus Rails Combo Wkshp June 23-27 Ann Arbor, Mich
Please visit http://LearnRuby.com for all the details.

Again, I think it comes down to pragmatism. It's not what these methods "should" return; it's what it's most -useful- for them to return.

///ark

···

On May 22, 2008, at 12:41 AM, Sebastian Hungerecker wrote:

Mark Hubbart wrote:

If a string is provided, then it must follow the same rules as the
appropriate literal representation.... This is the source of the

differences. So:

Integer("023") #=> 19
Float("023") #=> 23.0

But shouldn't Float("023") return an error in this case? After all "023" is
not a literal representation of a float (neither is "23").

Eric I. wrote:

My question is why doesn't Float know how to deal with prefixes such as
Hex? I wouldn't care if it tossed out invalid hex numbers such as 0x1h
but it should at least try. As far as I am concerned the only
difference between Float and Integer should be the return type, not what
types they can handle.

Well you're asking "why", and I suppose you'd have to address the
question to the core Ruby team. However, I can venture a guess, for
whatever that might be worth. And there are three elements to my
guess.

First, Float() and Integer() work like Ruby itself. In Ruby code you
can hardcode integer literals using 17 (dec), 021 (oct), or 0x11
(hex). But you can only hardcode floating point literals using base
ten. Admittedly, that's a bit of a punt since you'll probably ask why
Ruby works that way.

Second, I've never had the need to represent a floating point value as
a hexadecimal literal or string. With integers you sometimes need bit
masks and such. Perhaps there are domains where this would be very
useful. But I imagine most programmers don't typically run into
them. And like anything, people are more likely to do things that
they believe will be useful, or they scratch their own itches.

I think my main concern was this was yet another "gotcha" that only came up if you tested for it. My original conversion for strings to floats was a simple: x = Float(x) if (Float(x) rescue false). This works fine for "12", and "12.34" but crashes if I use "0x11" or any other hex value, something Integer does not. What I ended up having to do is:

temp = nil
temp = Float(x) if (Float(x) rescue false)
if temp == nil
   temp = Integer(x) if (Integer(x) rescue false)
end
if temp == nil
   x = 0
else
   x = temp
end

As you can see this is much more code, and that is before I add in more code for error handling.

And my third reason is that there might be ambiguity in how to
interpret such a string. The representation of floating point values
as a bit pattern is typically done using IEEE 754. So, if we wanted
to represent a PI as a floating point double as a hexadecimal
constant, I think it would be "0x400921fb54442d18". However that
could also be interpreted as the integer 4,614,256,656,552,045,848.

Given your original post, you seem to be thinking that hexadecimal
constants would include a "." to separate the whole part from the
fractional part. In that case, I imagine pi would be represented as
"0x3.243f6a8885a3".

Actually I wouldn't care if it couldn't handle floating point numbers in any base except 10 as it doesn't appear to be able to do so in other methods like sprintf or printf. I don't think it would have been that hard to allow Float to handle strings like '0x11' as the code has already been created for Integer.

But for those programmers out there who'd want some type of
functionality, they may not be unified in their preference for the
format -- IEEE 754 or with an included decimal point.

I don't know how satisfying you'll find those answers, but they're the
best I can do.

I have no problem with your replies and can see that maybe the original implementation was made to work correctly for a small subset of possible values rather than try to handle everything with possible problems. As I mentioned earlier I was trying to take the section on duck typing seriously and make my class handle as many reasonable inputs as possible. I will probably try to include arrays and strings like "17 4" as inputs once I finish the inputs for Integers, Floats, Rationals, and Strings in any combination.
I hadn't thought about adding the ability to display Rational numbers in other bases but that should be trivial, at least compared to Floating point numbers. I would use something like 0x11/0x4 to represent 17/4. Since the numerator and denominator of my Rational numbers are always Integers converting should be easy.

···

On May 19, 7:44 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> > wrote:

By the way, if you want to include such functionality in your Rational
project, the following Ruby snippets might be helpful.

To figure out how pi would be represented as an IEEE 754 encoded
value, I used the following Ruby code:

    "0x" + [Math::PI].pack("G").unpack("H*").first

If you're unfamiliar with the methods, you may be interested in
reading the documentation on Array#pack and String#unpack.

To figure out how pi would be represented in the other form, I used
this Ruby code:

    fractional_hex_digits = 12 # how many hex digits right of decimal
    "0x" +
      Math::PI.floor.to_s(16) +
      "." +
      ((Math::PI - Math::PI.floor) *
         16**fractional_hex_digits).floor.to_s(16)

If you plan on using any of this code, please check my work since it
comes with absolutely to warranties.

Best,

Eric

====

LearnRuby.com offers Rails & Ruby HANDS-ON public & ON-SITE
workshops.
   Ruby Fundamentals Wkshp June 16-18 Ann Arbor, Mich.
   Ready for Rails Ruby Wkshp June 23-24 Ann Arbor, Mich.
   Ruby on Rails Wkshp June 25-27 Ann Arbor, Mich.
   Ruby Plus Rails Combo Wkshp June 23-27 Ann Arbor, Mich
Please visit http://LearnRuby.com for all the details.

Hi,

···

In message "Re: Why doesn't Float() work the same as Integer()?" on Tue, 20 May 2008 11:30:12 +0900, "Eric I." <rubytraining@gmail.com> writes:

First, Float() and Integer() work like Ruby itself. In Ruby code you
can hardcode integer literals using 17 (dec), 021 (oct), or 0x11
(hex). But you can only hardcode floating point literals using base
ten. Admittedly, that's a bit of a punt since you'll probably ask why
Ruby works that way.

Because most of us would have hard time to guess how much 0x11.4 is.
Besides that, I don't see any usecase for converting hexadecimal
(integer) representation directly into float values.

              matz.

sort of, you can write this

x = Float(x) rescue Integer(x) rescue 0

but be aware, Float and Integer will handle a nil argument differently.

a @ http://codeforpeople.com/

···

On May 19, 2008, at 9:45 PM, Michael W. Ryder wrote:

temp = nil
temp = Float(x) if (Float(x) rescue false)
if temp == nil
temp = Integer(x) if (Integer(x) rescue false)
end
if temp == nil
x = 0
else
x = temp
end

As you can see this is much more code, and that is before I add in more code for error handling.

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Yukihiro Matsumoto wrote:

Because most of us would have hard time to guess how much 0x11.4 is.

I'd expect it to be 1 * 16**1 + 1 * 16**0 + 4 * 16**(-1)

···

--
NP: Depeche Mode - See You
Jabber: sepp2k@jabber.org
ICQ: 205544826

Yukihiro Matsumoto wrote:

Hi,

>First, Float() and Integer() work like Ruby itself. In Ruby code you
>can hardcode integer literals using 17 (dec), 021 (oct), or 0x11
>(hex). But you can only hardcode floating point literals using base
>ten. Admittedly, that's a bit of a punt since you'll probably ask why
>Ruby works that way.

Because most of us would have hard time to guess how much 0x11.4 is.
Besides that, I don't see any usecase for converting hexadecimal
(integer) representation directly into float values.

              matz.

Thank you for the reply. I wanted to convert strings to Floats first as it simplified some of a method's logic. The method allows Rational.new(3.5) and returns 7/2, it also allows Rational.new(3.5, 2) and returns 7/4. Converting from strings seemed to be a simple addition to the method and rather than having separate logic for Integers and Floats I wanted to just convert all Strings to Floats and then convert the Floats. Since I had already gone this far I decided to add support for any number that Ruby allows, this is where I ran into the "inconsistency" in the methods Float(x) and Integer(x).
As Ruby doesn't appear to support Floats in any base other than 10 I had no problem if it didn't convert '0x11.4' just like it wouldn't convert 'abcd'. But since it could convert valid Integers I was confused while it couldn't convert '0x11'.

···

In message "Re: Why doesn't Float() work the same as Integer()?" > on Tue, 20 May 2008 11:30:12 +0900, "Eric I." <rubytraining@gmail.com> writes:

That's what I'd said in my reply. And then, of course, we get this:

    xkcd: Geohashing

Not that a webcomic should drive language design. But not that it
shouldn't either.... :wink:

Eric

···

On May 21, 4:14 am, Yukihiro Matsumoto <m...@ruby-lang.org> wrote:

Besides that, I don't see any usecase for converting hexadecimal
(integer) representation directly into float values.

====

LearnRuby.com offers Rails & Ruby HANDS-ON public & ON-SITE
workshops.
   Ruby Fundamentals Wkshp June 16-18 Ann Arbor, Mich.
   Ready for Rails Ruby Wkshp June 23-24 Ann Arbor, Mich.
   Ruby on Rails Wkshp June 25-27 Ann Arbor, Mich.
   Ruby Plus Rails Combo Wkshp June 23-27 Ann Arbor, Mich
Please visit http://LearnRuby.com for all the details.

In article <14527A3C-F9BF-4E8A-9B48-3EA2D2EBE76A@gmail.com>,

···

ara.t.howard <ara.t.howard@gmail.com> wrote:

sort of, you can write this

x = Float(x) rescue Integer(x) rescue 0

but be aware, Float and Integer will handle a nil argument differently.

Why?

Francis

ara.t.howard wrote:

temp = nil
temp = Float(x) if (Float(x) rescue false)
if temp == nil
temp = Integer(x) if (Integer(x) rescue false)
end
if temp == nil
x = 0
else
x = temp
end

As you can see this is much more code, and that is before I add in more code for error handling.

sort of, you can write this

x = Float(x) rescue Integer(x) rescue 0

This works fine for me and returns values that I am expecting. Changing it slightly to:
x = (Float(x) rescue Integer(x) rescue 0).to_f
gives me the Float value I was looking for. I can live with this, just part of learning a new language is learning when something will not work the way you expect and how to work around it.
Thank you for the code. I am still learning how to use exceptions.

···

On May 19, 2008, at 9:45 PM, Michael W. Ryder wrote:

but be aware, Float and Integer will handle a nil argument differently.

a @ http://codeforpeople.com/
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

I would be very careful with converting Floats to Rationals. You know
that Rational.new(0.1) wouldn't return 1/10? If not you should read
about IEEE 754, which is the basis for Ruby's floating point numbers.

Regards,
Pit

···

2008/5/21 Michael W. Ryder <_mwryder@worldnet.att.net>:

The method allows Rational.new(3.5) and returns 7/2

Pit Capitain wrote:

The method allows Rational.new(3.5) and returns 7/2

I would be very careful with converting Floats to Rationals. You know
that Rational.new(0.1) wouldn't return 1/10? If not you should read
about IEEE 754, which is the basis for Ruby's floating point numbers.

I realize that my implementation will not work with all allowable Floats such as Infinity, NAN, etc. but I am not trying to cover everything, just some of the most common. I envision being able to use my version of the rational module to implement a command line calculator that could take "3.4 + 12 3/4" and return 16 3/20 or 16.15.
I can not see how you can say that 0.1 != 1/10. I tried looking up the standard but the paper I looked at, about implementing the standard in a language, made no mention of converting floating point numbers to rational numbers.

···

2008/5/21 Michael W. Ryder <_mwryder@worldnet.att.net>:

Regards,
Pit

Michael W. Ryder wrote:

I can not see how you can say that 0.1 != 1/10. I tried looking up the standard but the paper I looked at, about implementing the standard in a language, made no mention of converting floating point numbers to rational numbers.

Ruby uses binary numbers, not decimal numbers. In binary, 1/10 cannot be represented exactly, just like 1/3 cannot be represented exactly in decimal.

···

--
RMagick: http://rmagick.rubyforge.org/
RMagick 2: http://rmagick.rubyforge.org/rmagick2.html