What is the difference between Integer and Fixnum?
You never "use" Integer
. It is an abstract class whose job is to endow its children (Fixnum
and Bignum
) with methods. Under effectively no circumstances will you ever ask for an object's class and be told that it is an Integer
.
Ruby Numeric vs Integer
Numeric.descendants
#=> [BigDecimal, Date::Infinity, Integer, Fixnum, Float, Bignum, Rational, Complex]
So if you need to define a method for both Fixnum
and Float
you can do it in Numeric (not talking about the open classes monkeypatching issues)
How can a Fixnum (Integer) and a Float compare as equal in Ruby?
Are you sure that expressions like 0.9 == 0.9
is not guaranteed? I don't think so. It succeeds on my machine, and even though there is rounding error, the algorithm should always map the same literal expression to the same float with the same rounding error. For example, if the expression "0.9"
were to be expressed internally as 0.900001
, it will always be so. It doesn't get mapped sometimes to 0.900000
and sometimes to 0.900002
. So equality should be guaranteed.
Regarding comparison between Fixnum
and Float
, if a fixnum literal is converted to a float, it would also be mapped to the same float as if it were a float from the beginning, with the same rounding error. In other words, the following two processes end up with the same float:
- Literal
"1.0"
→ Some internal float with rounding error (say,0.999999
) - Literal
"1"
→ Internal fixnum1
→ Some internal float with rounding error (0.999999
)
Edit Or, as fmendez says, if integers are mapped internally precisely to a float, then floats that exactly correspond to an integer (like "1.0"
, "2.0"
, etc.) do not have any rounding error within the internal float expression. So equality would be guaranteed anyway.
12345.class returning 'Integer' not 'Fixnum' in Ruby
It depends on the Ruby version. From Ruby 2.4.0 we have just Integer
s, no more Fixnum
s and Bignum
s distinction
https://www.ruby-lang.org/en/news/2016/12/25/ruby-2-4-0-released/
Some `Fixnum` properties
In Ruby, most objects require memory to store their class and instance variables. Once this memory is allocated, Ruby represents each object by this memory location. When the object is assigned to a variable or passed to a function, it is the location of this memory that is passed, not the data at this memory. Singleton methods make use of this. When you define a singleton method, Ruby silently replaces the objects class with a new singleton class. Because each object stores its class, Ruby can easily replace an object's class with a new class that implements the singleton methods (and inherits from the original class).
This is no longer true for objects that are immediate values: true
, false
, nil
, all symbols, and integers that are small enough to fit within a Fixnum. Ruby does not allocate memory for instances of these objects, it does not internally represent the objects as a location in memory. Instead, it infers the instance of the object based on its internal representation. What this means is twofold:
The class of each object is no longer stored in memory at a particular location, and is instead implicitly determined by the type of immediate object. This is why Fixnums cannot have singleton methods.
Immediate objects with the same state (e.g., two Fixnums of integer 2378) are actually the same instance. This is because the instance is determined by this state.
To get a better sense of this, consider the following operations on a Fixnum:
>> x = 3 + 7
=> 10
>> x.object_id == 10.object_id
=> true
>> x.object_id == (15-5).object_id
=> true
Now, consider them using strings:
>> x = "a" + "b"
=> "ab"
>> x.object_id == "ab".object_id
=> false
>> x.object_id == "Xab"[1...3].object_id
=> false
>> x == "ab"
=> true
>> x == "Xab"[1...3]
=> true
The reason the object ids of the Fixnums are equal is that they're immediate objects with the same internal representation. The strings, on the other hand, exist in allocated memory. The object id of each string is the location of its object state in memory.
Some low-level information
To understand this, you have to understand how Ruby (at least 1.8 and 1.9) treat Fixnums internally. In Ruby, all objects are represented in C code by variables of type VALUE
. Ruby imposes the following requirements for VALUE
:
The type VALUE is is the smallest integer of sufficient size to hold a pointer. This means, in C, that
sizeof(VALUE) == sizeof(void*)
.Any non-immediate object must be aligned on a 4-byte boundary. This means that any object allocated by Ruby will have address
4*i
for some integeri
. This also means that all pointers have zero values in their two least significant bits.
The first requirement allows Ruby to store both pointers to objects and immediate values in a variable of type VALUE
. The second requirement allows Ruby to detect Fixnum and Symbol objects based on the two least significant bits.
To make this more concrete, consider the internal binary representation of a Ruby object z
, which we'll call Rz
in a 32-bit architecture:
MSB LSB
3 2 1
1098 7654 3210 9876 5432 1098 7654 32 10
XXXX XXXX XXXX XXXX XXXX XXXX XXXX AB CD
Ruby then interprets Rz
, the representation of z
, as follows:
If
D==1
, thenz
is a Fixnum. The integer value of this Fixnum is stored in the upper 31 bits of the representation, and is recovered by performing an arithmetic right shift to recover the signed integer stored in these bits.Three special representations are tested (all with
D==0
)- if
Rz==0
, thenz
isfalse
- if
Rz==2
, thenz
istrue
- if
Rz==4
, thenz
isnil
- if
If
ABCD == 1110
, then 'z' is a Symbol. The symbol is converted into a unique ID by right-shifting the eight least-significant bits (i.e.,z>>8
in C). On 32-bit architectures, this allows 2^24 different IDs (over 10 million). On 64-bit architectures, this allows 2^48 different IDs.Otherwise,
Rz
represents an address in memory for an instance of a Ruby object, and the type ofz
is determined by the class information at that location.
Size of numeric data types in Ruby
I know that Ruby has Float for real, Fixnum and Bignum for int.
This is not true.
Float
does not represent real numbers, it represents floating point numbers. In fact, in the general case, representing real numbers in a physical computer is impossible, as it requires unbounded memory.
Fixnum
and Bignum
are not part of Ruby. Ruby only has Integer
. The Ruby Specification allows different implementations to have implementation-specific subclasses, but these are then specific to that particular implementation (e.g. YARV, Opal, TruffleRuby, Artichoke, JRuby, IronRuby, MRuby, etc.), they don't have anything to do with Ruby.
In fact, even knowing the implementation is not enough, you have to know the exact version. For example, YARV had Fixnum
and Bignum
as subclasses in the past, but now it doesn't anymore, it only has Integer
. And even back when it had them, that was still not enough, because they actually had different sizes depending on the platform.
But what about sizes of this types?
a = 1.23 // size of one Float in bytes?
b = 1 // size of one Fixnum in bytes?
c = 2**65 // = size of one Bignum in bytes?
I am trying to find a standard or specification
Here is what the ISO/IEC 30170:2012 Information technology — Programming languages — Ruby specification has to say on the matter [bold emphasis mine]:
15.2.8
Integer
15.2.8.1 General description
Instances of the class
Integer
represent integers. The ranges of these integers are unbounded. However the actual values computable depend on resource limitations, and the behavior when the resource limits are exceeded is implementation-defined.[…]
Subclasses of the class
Integer
may be defined as built-in classes. In this case:
- The class
Integer
shall not have its direct instances. Instead of a direct instance of the classInteger
, a direct instance of a subclass of the classInteger
shall be created.- Instance methods of the class
Integer
need not be defined in the classInteger
itself if the instance methods are defined in all subclasses of the classInteger
.- For each subclass of the class
Integer
, the ranges of the values of its instances may be bounded.
The ISO Ruby Language Specification does not mandate any particular size or representation for Integer
s, nor does it specify any methods for querying this information.
15.2.9
Float
15.2.9.1 General description
Instances of the class
Float
represent floating-point numbers.
The precision of the value of an instance of the classFloat
is implementation-defined; however, if the underlying system of a conforming processor supports IEC 60559, the representation of an instance of the classFloat
shall be the 64-bit double format as specified in IEC 60559, 3.2.2.
The ISO Ruby Language Specification does not mandate any particular size or representation for Float
s, unless the underlying system supports ISO/IEC 60559, in which case the representation must be as an ISO/IEC 60559 binary64 double float. The ISO Ruby Language Specification does not specify any methods for querying this information.
The ruby/spec does not say anything about the size or precision of Float
. In fact, it is very careful to not say anything. For example, if you look at the spec for Float#prev_float
, you can see that they are very careful to specify the behavior of Float#prev_float
without ever referring to the actual precision.
The ruby/spec for Integer#size
does say something about the sizes of specific machine integers in bytes. However, unfortunately, ruby/spec is kind of a mixture between specifications for the behavior of the Ruby Programming Language and the behavior of the YARV Ruby Implementation. I have the feeling that this spec is more like the latter.
For example, the cutoff point between fixnums and bignums in YARV is 231 on 32 bit platforms and 263 on 64 bit platforms, but on JRuby, it is 264 on both 32 bit and 64 bit platforms (and I think TruffleRuby is the same). So, 3000000000 will be a bignum on 32 bit YARV, but a fixnum on 64 bit YARV and JRuby, and 10000000000000000000 will be a bignum on both 32 bit and 64 bit YARV, but will be a fixnum even on 32 bit JRuby. For Opal, I think the cutoff point is different again, I think it is 253. Other implementations may not even distinguish between fixnums and bignums at all, or they may have three or more different kinds of integers.
Also, it is very important to remember that this spec only specifies the return value of the method Integer#size
. Nowhere does it say that this is actually how an Integer
must be represented in memory.
By the way, you may be confused why I am talking about fixnums and bignums in YARV, when I said above that Fixnum
and Bignum
have been removed from YARV. Well, the reason is that the separate classes have been removed, but the optimization is still there. Which is another thing: the ISO Ruby Language Specification says that you are allowed to have implementation-specific subclasses of Integer
, but it doesn't say what those classes are for. Neither does the ISO Ruby Language Specification force implementors to have optimized implementations for their subclasses, nor does it force implementors to have subclasses for their implementation-specific optimizations.
Compare that to YARV's flonums which are an optimized representation of 62 bit Float
s, but they don't have their own class.
So, in (not so) short: the ISO Ruby Language Specification does not say anything about the sizes of Integer
s, but it does say that if the underlying system supports ISO/IEC 60559, then the representation must be an ISO/IEC 60559 binary64 double float. It does, however, say nothing about the size or representation for cases where the underlying system does not support ISO/IEC 60559.
The ruby/spec is careful not to specify anything about the sizes of Float
s, but it does specify the return value of the Integer#size
method. It does, however, not specify that this return value must in any way correspond to how Integer
s are actually represented.
Here's what the RDoc for Integer#size
in YARV has to say [bold emphasis mine]:
size
→int
Returns the number of bytes in the machine representation of
int
(machine dependent).
So, it only says that it returns the number of bytes the Integer
would have in the machine representation, but not that this is necessarily the way that it is actually represented. And it clearly states that the value is machine dependent.
Ruby Fixnum comparison
If puts r['effortRemaining'].inspect
comes out in quote marks, that means it is a string and you need to convert it to a number before you compare it.
This should work:
if r['effortRemaining'].to_f > 0
Related Topics
Finding Out Current Index in Each Loop (Ruby)
How to Decompress Gzip String in Ruby
Ruby: Dynamically Generate Attribute_Accessor
How to Run Ruby and Git Commands in One Place on Windows
Why Doesn't Minitest::Spec Have a Wont_Raise Assertion
Why Isn't 'Method=' Treated the Same as Any Other Method
Ubuntu Rails Install Fails on Zlib
Using Factory_Girl in Rails with Associations That Have Unique Constraints. Getting Duplicate Errors
Default Task for Namespace in Rake
Ruby on Rails: Can You Put Ruby Code in a Yaml Config File
Get the Value of an Instance Variable Given Its Name
Put a Link in a Flash[:Notice]
Looping Through Bits in an Integer, Ruby
How to Debug in Rubymine 4.5 Using Ruby 1.9.3
Return Index of All Occurrences of a Character in a String in Ruby
How to Embed Regular Expressions in Other Regular Expressions in Ruby
How to Get Sinatra to Auto-Reload the File After Each Change
How to Get Readline Support in Irb Using Rvm on Ubuntu 11.10