# Is 2.0 Integer or Float?

Discussion in 'Ruby' started by S. Robert James, Nov 14, 2006.

1. ### S. Robert JamesGuest

I'd like to be able to do:

x = 2.0
assert x.integral?

the :integer method returns false in this case.
What would be a good way to write a different method to check?

S. Robert James, Nov 14, 2006

2. ### James Edward Gray IIGuest

On Nov 14, 2006, at 10:35 AM, S. Robert James wrote:

> I'd like to be able to do:
>
> x = 2.0
> assert x.integral?
>
> the :integer method returns false in this case.
> What would be a good way to write a different method to check?

>> 2.0.is_a? Float

=> true
>> 2.0.is_a? Integer

=> false

James Edward Gray II

James Edward Gray II, Nov 14, 2006

3. ### Szymon RozgaGuest

Hope the following helps:

irb(main):001:0> 2.0.class
=> Float
irb(main):002:0> 2.class
=> Fixnum
irb(main):003:0> 2.0.is_a?(Float)
=> true
irb(main):004:0> 2.0.is_a?(Fixnum)
=> false
irb(main):005:0> 2.is_a?(Float)
=> false
irb(main):006:0> 2.is_a?(Fixnum)
=> true

-Szymon

On Nov 14, 11:34 am, "S. Robert James" <> wrote:
> I'd like to be able to do:
>
> x = 2.0
> assert x.integral?
>
> the :integer method returns false in this case.
> What would be a good way to write a different method to check?

Szymon Rozga, Nov 14, 2006
4. ### Tim PeaseGuest

On 11/14/06, S. Robert James <> wrote:
> I'd like to be able to do:
>
> x = 2.0
> assert x.integral?
>
> the :integer method returns false in this case.
> What would be a good way to write a different method to check?
>

class Numeric
def is_integer?
Integer(self) == self
end
end

2.0.is_integer? #=> true
2.1.is_integer? #=> false
2.is_integer? #=> true

Blessings,
TwP

Tim Pease, Nov 14, 2006
5. ### Guest

On Nov 14, 2006, at 11:35 AM, S. Robert James wrote:

> I'd like to be able to do:
>
> x = 2.0
> assert x.integral?
>
> the :integer method returns false in this case.
> What would be a good way to write a different method to check?

Maybe it is just me, I don't have a lot of experience with floating
point
issues, but this request has a bad smell to it. Once you've decided to
model something with floating point values it seems a bit unusual to
want
to know if any particular value happens to be the exact floating point
representation of an integer. Isn't the entire notion of equality
somewhat
ambiguous in the floating point world? I thought this is usually
handled by
asking if two values are within some delta (also represented as a
floating
point value) of each other.

Any numerical computation folks out there who can share their wisdom?

Maybe the value should be modeled as an integer with different units
of dollars to model monetary values.

Gary Wright

, Nov 14, 2006
6. ### Wilson BilkovichGuest

On 11/14/06, <> wrote:
>
> On Nov 14, 2006, at 11:35 AM, S. Robert James wrote:
>
> > I'd like to be able to do:
> >
> > x = 2.0
> > assert x.integral?
> >
> > the :integer method returns false in this case.
> > What would be a good way to write a different method to check?

>
> Maybe it is just me, I don't have a lot of experience with floating
> point
> issues, but this request has a bad smell to it. Once you've decided to
> model something with floating point values it seems a bit unusual to
> want
> to know if any particular value happens to be the exact floating point
> representation of an integer. Isn't the entire notion of equality
> somewhat
> ambiguous in the floating point world? I thought this is usually
> handled by
> asking if two values are within some delta (also represented as a
> floating
> point value) of each other.
>
> Any numerical computation folks out there who can share their wisdom?
>
> Maybe the value should be modeled as an integer with different units
> instead of floating point? For example using units of pennies instead
> of dollars to model monetary values.
>

IEEE floating point can store an exact representation of any integer
that the fp number is large enough to contain.
I've never used it this way, but supposedly that is used to handle
53-bit ints on platforms that have 64-bit floats and only 32-bit ints.

That may or may not be what the OP is trying to do.

Wilson Bilkovich, Nov 14, 2006
7. ### James Edward Gray IIGuest

On Nov 14, 2006, at 2:21 PM, Wilson Bilkovich wrote:

> IEEE floating point can store an exact representation of any integer
> that the fp number is large enough to contain.
> I've never used it this way, but supposedly that is used to handle
> 53-bit ints on platforms that have 64-bit floats and only 32-bit ints.
>
> That may or may not be what the OP is trying to do.

I'm pretty sure Lua uses floats for everything, for exactly this reason.

James Edward Gray II

James Edward Gray II, Nov 14, 2006
8. ### Joel VanderWerfGuest

James Edward Gray II wrote:
> On Nov 14, 2006, at 2:21 PM, Wilson Bilkovich wrote:
>
>> IEEE floating point can store an exact representation of any integer
>> that the fp number is large enough to contain.
>> I've never used it this way, but supposedly that is used to handle
>> 53-bit ints on platforms that have 64-bit floats and only 32-bit ints.
>>
>> That may or may not be what the OP is trying to do.

>
> I'm pretty sure Lua uses floats for everything, for exactly this reason.

How does that work? Is there an 11-bit pattern that signifies "use the
remaining 53 bits as a integer"? Do math library functions respect this?

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Joel VanderWerf, Nov 14, 2006
9. ### James Edward Gray IIGuest

On Nov 14, 2006, at 2:29 PM, Joel VanderWerf wrote:

> James Edward Gray II wrote:
>> On Nov 14, 2006, at 2:21 PM, Wilson Bilkovich wrote:
>>> IEEE floating point can store an exact representation of any integer
>>> that the fp number is large enough to contain.
>>> I've never used it this way, but supposedly that is used to handle
>>> 53-bit ints on platforms that have 64-bit floats and only 32-bit
>>> ints.
>>>
>>> That may or may not be what the OP is trying to do.

>> I'm pretty sure Lua uses floats for everything, for exactly this
>> reason.

>
> How does that work? Is there an 11-bit pattern that signifies "use
> the remaining 53 bits as a integer"? Do math library functions
> respect this?

I have no idea how they do what they do:

http://lua-users.org/wiki/FloatingPoint

James Edward Gray II

James Edward Gray II, Nov 14, 2006
10. ### Sander LandGuest

On 11/14/06, Joel VanderWerf <> wrote:
> How does that work? Is there an 11-bit pattern that signifies "use the
> remaining 53 bits as a integer"? Do math library functions respect this?

53 bits is just the mantissa size.
imagine using scientific notation a * 10^b with a<1 and 3 decimal
digits, this gives you accurate integers up to 1000.
999 => 0.999 * 10^3 exact
1001=> 0.100 * 10^4 overflowed

Sander Land, Nov 14, 2006
11. ### Joel VanderWerfGuest

Sander Land wrote:
> On 11/14/06, Joel VanderWerf <> wrote:
>> How does that work? Is there an 11-bit pattern that signifies "use the
>> remaining 53 bits as a integer"? Do math library functions respect this?

>
> 53 bits is just the mantissa size.
> imagine using scientific notation a * 10^b with a<1 and 3 decimal
> digits, this gives you accurate integers up to 1000.
> 999 => 0.999 * 10^3 exact
> 1001=> 0.100 * 10^4 overflowed

Ok, so they aren't doing anything exceptional with the format. There's
no special switching going on, just normal floating point math with
integer values.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Joel VanderWerf, Nov 14, 2006
12. ### Patrick HurleyGuest

But depending upon how the "integer" was generated, it may still make
more sense to use an epsilon in the test (which certainly has the
"smell" that was mentioned earlier)

Integer(100.0 * 9.95) == 995 => false
(100.0 * 9.95) - 995.0 <= Float::EPSILON => true

# So you find yourself tempted to do this
class Float
def like_an_int
(self - self.round).abs <= Float::EPSILON
end
end

(100.0 * 9.95).like_an_int => false

On my system Float::EPSILON = 2.22044604925031e-016
(100.0 * 9.95) - 995.0 => -1.13686837721616e-013

Which is way bigger than EPSILON, it turns out you need to scale your
"EPSILON" by the relative magnitude of the numbers being compared.
This way leads to madness and general discomfort --> if you find
yourself in this neighborhood, switch to rational numbers (or scaled
integers), you will be happier.

pth

Patrick Hurley, Nov 14, 2006
13. ### Bernard KenikGuest

----- Original Message -----
From: "S. Robert James" <>
Newsgroups: comp.lang.ruby
To: "ruby-talk ML" <>
Sent: Tuesday, November 14, 2006 11:35 AM
Subject: Is 2.0 Integer or Float?

> I'd like to be able to do:
>
> x = 2.0
> assert x.integral?
>
> the :integer method returns false in this case.
> What would be a good way to write a different method to check?
>

x.class => Float 2.0 is a float not an integer

Bernard Kenik, Nov 15, 2006
14. ### Dale MartensonGuest

Paul Lutus wrote:
> Bernard Kenik wrote:
>
>>> the :integer method returns false in this case.
>>> What would be a good way to write a different method to check?
>>>

>> x.class => Float 2.0 is a float not an integer

>
> The OP is trying to establish whether the _content_ of the float
> variable is
> an integer, not whether the variable has float type. That is relatively
> easy to establish.

Sorry to join this conversation late, but to me this is a strange
question. Floats are never integers. Integers are counting numbers with
exact values over a certain range determined by their internal
representation. While floating point numbers are approximations which
suffer from errors of precision. They may approach an integer bound and
yet never achieve it. So the question is what approximation is adequate
to say that a float is the integer that it approaches. What is close
enough?

Example:

irb(main):124:0> def is_integer(f)
irb(main):125:1> ((f.ceil - f).remainder(1).abs < 0.0000000001) or
((f.floor - f
).remainder(1).abs < 0.0000000001)
irb(main):126:1> end
=> nil
irb(main):127:0> n = 0.1
=> 0.1
irb(main):128:0> 100.times { puts "#{n} is a integer: #{is_integer(n)}";
n += 0.
1 }
0.1 is a integer: false
0.2 is a integer: false
0.3 is a integer: false
0.4 is a integer: false
0.5 is a integer: false
0.6 is a integer: false
0.7 is a integer: false
0.8 is a integer: false
0.9 is a integer: false
1.0 is a integer: true
1.1 is a integer: false
1.2 is a integer: false
1.3 is a integer: false
1.4 is a integer: false
1.5 is a integer: false
1.6 is a integer: false
1.7 is a integer: false
1.8 is a integer: false
1.9 is a integer: false
2.0 is a integer: true
2.1 is a integer: false
2.2 is a integer: false
2.3 is a integer: false
2.4 is a integer: false
2.5 is a integer: false
2.6 is a integer: false
2.7 is a integer: false
2.8 is a integer: false
2.9 is a integer: false
3.0 is a integer: true
3.1 is a integer: false
3.2 is a integer: false
3.3 is a integer: false
3.4 is a integer: false
3.5 is a integer: false
3.6 is a integer: false
3.7 is a integer: false
3.8 is a integer: false
3.9 is a integer: false
4.0 is a integer: true
4.1 is a integer: false
4.2 is a integer: false
4.3 is a integer: false
4.4 is a integer: false
4.5 is a integer: false
4.6 is a integer: false
4.7 is a integer: false
4.8 is a integer: false
4.9 is a integer: false
5.0 is a integer: true
5.1 is a integer: false
5.2 is a integer: false
5.3 is a integer: false
5.4 is a integer: false
5.5 is a integer: false
5.6 is a integer: false
5.7 is a integer: false
5.8 is a integer: false
5.9 is a integer: false
5.99999999999999 is a integer: true
6.09999999999999 is a integer: false
6.19999999999999 is a integer: false
6.29999999999999 is a integer: false
6.39999999999999 is a integer: false
6.49999999999999 is a integer: false
6.59999999999999 is a integer: false
6.69999999999999 is a integer: false
6.79999999999999 is a integer: false
6.89999999999999 is a integer: false
6.99999999999999 is a integer: true
7.09999999999999 is a integer: false
7.19999999999999 is a integer: false
7.29999999999999 is a integer: false
7.39999999999999 is a integer: false
7.49999999999999 is a integer: false
7.59999999999999 is a integer: false
7.69999999999999 is a integer: false
7.79999999999999 is a integer: false
7.89999999999999 is a integer: false
7.99999999999999 is a integer: true
8.09999999999999 is a integer: false
8.19999999999999 is a integer: false
8.29999999999999 is a integer: false
8.39999999999999 is a integer: false
8.49999999999999 is a integer: false
8.59999999999999 is a integer: false
8.69999999999999 is a integer: false
8.79999999999998 is a integer: false
8.89999999999998 is a integer: false
8.99999999999998 is a integer: true
9.09999999999998 is a integer: false
9.19999999999998 is a integer: false
9.29999999999998 is a integer: false
9.39999999999998 is a integer: false
9.49999999999998 is a integer: false
9.59999999999998 is a integer: false
9.69999999999998 is a integer: false
9.79999999999998 is a integer: false
9.89999999999998 is a integer: false
9.99999999999998 is a integer: true

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

Dale Martenson, Nov 16, 2006
15. ### Dale MartensonGuest

Paul Lutus wrote:
> Dale Martenson wrote:
>
>> Paul Lutus wrote:

>
> All your examples prove is that floats are not integers. But, hear me on
> this, integers really are integers, no matter where they are located,
> assuming they do not overflow the range of the variable in which they
> are
> stored.
>
> ----------------------------------------
> #!/usr/bin/ruby -w
>
> 0.upto(1e6) do |i|
> fi = i.to_f
> puts "Error: #{i}" if(i != fi)
> end
> ----------------------------------------
>
> The silence was deafening. I lost patience with more repetitions, but I
> think I know the outcome.
>
> You should know that many projects store integers in float variables in
> cases where the float variable has more available bits of precision that
> the platform's integer data type. Those who do this know there is no
> downside -- the integer stored in the float variable won't start
> misbehaving itself just because of its new, upscale quarters.

Yes, you can store integers in floats. This is usually done with the
exponent left at zero and the size of the mantissa limits the range of
valid integers. If the exponent must be used, it becomes a computed
value that is an approximation.

Using irb,

irb(main):163:0> 1e6.class => Float
irb(main):164:0> 1e22.to_i => 10000000000000000000000
irb(main):165:0> 1e23.to_i => 99999999999999991611392

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

Dale Martenson, Nov 17, 2006
16. ### Dale MartensonGuest

Dale Martenson wrote:
> Paul Lutus wrote:
>> Dale Martenson wrote:
>>
>>> Paul Lutus wrote:

>> You should know that many projects store integers in float variables in
>> cases where the float variable has more available bits of precision that
>> the platform's integer data type. Those who do this know there is no
>> downside -- the integer stored in the float variable won't start
>> misbehaving itself just because of its new, upscale quarters.

I agree that storing integers in floats is possible as long as you only
use integer values for your computations and you do not exceed a
mantissa's precision that everything will be wonderful.

If this is the world you wish to limit yourself to then:

def is_integer(f)
f.remainder(1) == 0
end

would be adequate as a test to determine is a value stored in a float is
an integer, but this will fail on many computed values that involve
non-integer values even if the expected result should be an integer
value.

I personally don't see a valid application in Ruby since Fixnum and
Bignum handle precision well beyond that of Float.

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

Dale Martenson, Nov 17, 2006