[Fwd: Re: [Pharo-dev] Float hierarchy for 64-bit Spur]

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

[Fwd: Re: [Pharo-dev] Float hierarchy for 64-bit Spur]

Ben Coman

(sorry, I didn't notice the cross-post)

Eliot Miranda wrote:
> Hi All,
>
>     64-bit Spur can usefully provide an immediate float, a 61-bit subset
> of the ieee double precision float.  

I wonder if class SmallDouble would be more intention revealing?

In practice 61 bits will be "more than enough"(tm) for anyone. But I can
envisage in a business environment environment software needing to
comply with (sometimes irrelevant) feature checklists, with one of those
likely being full 64 bit compliant IEEE Doubles.  Can we have such a
class, to which 61 bit floats are auto-promoted as required?


> The scheme steals bits from the
> mantissa to use for the immediate's 3-bit tag pattern.  So values have
> the same precision as ieee doubles, but can only represent the subset
> with exponents between 10^-38 and 10^38, the single-precision range.  
> The issue here is how to organize the class hierarchy.

>
> The approach that looks best to me is to modify class Float to be an
> abstract class, and add two subclasses, BoxedFloat and SmallFloat, such
> that existing boxed instances of Float outside the SmallFloat range will
> become instances of BoxedFloat and instances within that range will be
> replaced by references to the relevant SmallFloat.
>

My first few pages of search results lead to a few references in
conversation, but nothing that described what a boxed float is. Can
someone explain?

btw, http://www.ctan.org/pkg/float
also mentioned boxed float, ruled float and plain­top float
Anyone familiar with those?



> With this approach ...
>
> - Float pi etc can still be used, even though they will answer instances
> of SmallFloat.  But tests such as "self assert: result class == Float."
> will need to be rewritten to e.g.  "self assert: result isFloat".  

This is probably a good change anyway.

>
> - BoxedFloat and SmallFloat will not be mentioned much at all since
> floats print themselves literally, and so the fact that the classes have
> changed won't be obvious.
>
> - the boxed Float primitives (receiver is a boxed float) live in
> BoxedFloat and the immediate ones live in SmallFloat.  Making SmallFloat
> a subclass of Float** poses problems for all the primitives that do a
> super send to retry, since the boxed Float prims will be above the
> unboxed ones and so the boxed ones would have to test for an immediate
> receiver.

** do you mean the current Float, or after Float become abstract?

>
>
> An alternative, that VW took (because it has both Float and Double) is
> to add a superclass, e.g. LimitedPrecisionReal, move most of the methods
> into it, and keep Float as Float, and add SmallFloat as a subclass of
> LimitedPrecisionReal.  Then while class-side methods such as pi would
> likely be implemented in LimitedPrecisionReal class, sends to Float to
> access them find them via inheritance.  An automatic reorganization
> which moves only primitives out of LimitedPrecisionReal is easy to write.
>

A Float is defined as a limited precision real [1] having several types
of precision, so I like the first option.

[1] http://en.wikipedia.org/wiki/Floating_point

cheers -ben



Reply | Threaded
Open this post in threaded view
|

Re: [Fwd: Re: [Pharo-dev] Float hierarchy for 64-bit Spur]

Eliot Miranda-2
 
Hi Ben,

On Thu, Nov 20, 2014 at 7:00 PM, Ben Coman <[hidden email]> wrote:

(sorry, I didn't notice the cross-post)

Thanks, Ben.

Eliot Miranda wrote:
Hi All,

    64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 

I wonder if class SmallDouble would be more intention revealing?

In practice 61 bits will be "more than enough"(tm) for anyone. But I can envisage in a business environment environment software needing to comply with (sometimes irrelevant) feature checklists, with one of those likely being full 64 bit compliant IEEE Doubles.  Can we have such a class, to which 61 bit floats are auto-promoted as required?


Just as SmallInteger is seamless with the large integers, so SmallFloat is seamless with boxed Float.  The SmallFloat representation is used where ever possible, since it is faster both to decode (no memory fetch) and to encode (no allocation).  But operations overflow into the boxed representation if outside the SmallFloat range.


The scheme steals bits from the mantissa to use for the immediate's 3-bit tag pattern.  So values have the same precision as ieee doubles, but can only represent the subset with exponents between 10^-38 and 10^38, the single-precision range.  The issue here is how to organize the class hierarchy.


The approach that looks best to me is to modify class Float to be an abstract class, and add two subclasses, BoxedFloat and SmallFloat, such that existing boxed instances of Float outside the SmallFloat range will become instances of BoxedFloat and instances within that range will be replaced by references to the relevant SmallFloat.


My first few pages of search results lead to a few references in
conversation, but nothing that described what a boxed float is. Can
someone explain?

Boxed datatypes are those where the data is held in a structure (e.g. an object) and accessed throguh a pointer.  So most Smalltalk objects are "boxed", for example, large integers, points, etc.  But some datatypes (immediate SmallIntegers, and in Spur, the Characters, and in languages like C, all basic numeric types) are represented as pure values.

 
btw, http://www.ctan.org/pkg/float
also mentioned boxed float, ruled float and plain­top float
Anyone familiar with those?

Hmmm, never heard of ruled and plaintop floats.  I'd like to know too.


With this approach ...

- Float pi etc can still be used, even though they will answer instances of SmallFloat.  But tests such as "self assert: result class == Float." will need to be rewritten to e.g.  "self assert: result isFloat". 

This is probably a good change anyway.


- BoxedFloat and SmallFloat will not be mentioned much at all since floats print themselves literally, and so the fact that the classes have changed won't be obvious.

- the boxed Float primitives (receiver is a boxed float) live in BoxedFloat and the immediate ones live in SmallFloat.  Making SmallFloat a subclass of Float** poses problems for all the primitives that do a super send to retry, since the boxed Float prims will be above the unboxed ones and so the boxed ones would have to test for an immediate receiver.

** do you mean the current Float, or after Float become abstract?

The former.  If Float stays unchanged and one tries to add SmallFloat as a subclass then one hits the primitive failure problem.  If SmallFloat doesn't inherit from BoxedFloat (when Float is abstract with BoxedFloat and SmallFloat as subclasses), or if SmallFloat doesn't inherit from Float (when LimitedPrecisionReal is abstract, and BoxedFloat and SmallFloat inherit from it) then there's no such problem.




An alternative, that VW took (because it has both Float and Double) is to add a superclass, e.g. LimitedPrecisionReal, move most of the methods into it, and keep Float as Float, and add SmallFloat as a subclass of LimitedPrecisionReal.  Then while class-side methods such as pi would likely be implemented in LimitedPrecisionReal class, sends to Float to access them find them via inheritance.  An automatic reorganization which moves only primitives out of LimitedPrecisionReal is easy to write.


A Float is defined as a limited precision real [1] having several types
of precision, so I like the first option.

[1] http://en.wikipedia.org/wiki/Floating_point

cheers -ben

OK, thanks! 

--
best,
Eliot
Reply | Threaded
Open this post in threaded view
|

Re: [Fwd: Re: [Pharo-dev] Float hierarchy for 64-bit Spur]

Ben Coman
 
Eliot Miranda wrote:

>
> On Thu, Nov 20, 2014 at 7:00 PM, Ben Coman <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>
>     Eliot Miranda wrote:
>
>         Hi All,
>
>             64-bit Spur can usefully provide an immediate float, a
>         61-bit subset of the ieee double precision float.
>
>
>     I wonder if class SmallDouble would be more intention revealing?
>
>     In practice 61 bits will be "more than enough"(tm) for anyone. But I
>     can envisage in a business environment environment software needing
>     to comply with (sometimes irrelevant) feature checklists, with one
>     of those likely being full 64 bit compliant IEEE Doubles.  Can we
>     have such a class, to which 61 bit floats are auto-promoted as required?
>
>
>
> Just as SmallInteger is seamless with the large integers, so SmallFloat
> is seamless with boxed Float.  The SmallFloat representation is used
> where ever possible, since it is faster both to decode (no memory fetch)
> and to encode (no allocation).  But operations overflow into the boxed
> representation if outside the SmallFloat range.
>
>

(btw, rather than SmallFloat and BoxedFloat, I think SmallFloat and
LargeFloat would align better with the Integer hierarchy.)

So I understand that immediate types will overflow to boxes types :)

To try to be more clear, integers don't have a well defined size/format.
  It varies with architecture word size.  So SmallInteger and
LargeInteger are reasonable descriptions.  But floats have a well
defined format defined by IEEE. Since you are pivoting around the IEEE
Double format (you define it as "61-bit subset of the ieee double
precision float"), rather than generic SmallFloat and LargeFloat, use
SmallDouble and LargeDouble. (anyway, maybe I'm off track. Its not a big
deal).


>
>
>     My first few pages of search results lead to a few references in
>     conversation, but nothing that described what a boxed float is. Can
>     someone explain?
>
>
> Boxed datatypes are those where the data is held in a structure (e.g. an
> object) and accessed throguh a pointer.  So most Smalltalk objects are
> "boxed", for example, large integers, points, etc.  But some datatypes
> (immediate SmallIntegers, and in Spur, the Characters, and in languages
> like C, all basic numeric types) are represented as pure values.
>

Thanks.

cheers -ben
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: [Vm-dev] [Fwd: Re: [Pharo-dev] Float hierarchy for 64-bit Spur]

Eliot Miranda-2

Hi Ben,

On Nov 20, 2014, at 8:42 PM, Ben Coman <[hidden email]> wrote:

> Eliot Miranda wrote:
>> On Thu, Nov 20, 2014 at 7:00 PM, Ben Coman <[hidden email] <mailto:[hidden email]>> wrote:
>>    Eliot Miranda wrote:
>>        Hi All,
>>            64-bit Spur can usefully provide an immediate float, a
>>        61-bit subset of the ieee double precision float.     I wonder if class SmallDouble would be more intention revealing?
>>    In practice 61 bits will be "more than enough"(tm) for anyone. But I
>>    can envisage in a business environment environment software needing
>>    to comply with (sometimes irrelevant) feature checklists, with one
>>    of those likely being full 64 bit compliant IEEE Doubles.  Can we
>>    have such a class, to which 61 bit floats are auto-promoted as required?
>> Just as SmallInteger is seamless with the large integers, so SmallFloat is seamless with boxed Float.  The SmallFloat representation is used where ever possible, since it is faster both to decode (no memory fetch) and to encode (no allocation).  But operations overflow into the boxed representation if outside the SmallFloat range.
>
> (btw, rather than SmallFloat and BoxedFloat, I think SmallFloat and LargeFloat would align better with the Integer hierarchy.)
>
> So I understand that immediate types will overflow to boxes types :)
>
> To try to be more clear, integers don't have a well defined size/format.  It varies with architecture word size.  So SmallInteger and LargeInteger are reasonable descriptions.  But floats have a well defined format defined by IEEE. Since you are pivoting around the IEEE Double format (you define it as "61-bit subset of the ieee double precision float"), rather than generic SmallFloat and LargeFloat, use SmallDouble and LargeDouble. (anyway, maybe I'm off track. Its not a big deal).

Ah, I like this.  Thanks.



>>    My first few pages of search results lead to a few references in
>>    conversation, but nothing that described what a boxed float is. Can
>>    someone explain?
>> Boxed datatypes are those where the data is held in a structure (e.g. an object) and accessed throguh a pointer.  So most Smalltalk objects are "boxed", for example, large integers, points, etc.  But some datatypes (immediate SmallIntegers, and in Spur, the Characters, and in languages like C, all basic numeric types) are represented as pure values.
>
> Thanks.
>
> cheers -ben

Eliot (phone)
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: [Vm-dev] [Fwd: Re: [Pharo-dev] Float hierarchy for 64-bit Spur]

Ben Coman
 
Eliot Miranda wrote:

>  
> Hi Ben,
>
> On Nov 20, 2014, at 8:42 PM, Ben Coman <[hidden email]> wrote:
>
>> Eliot Miranda wrote:
>>> On Thu, Nov 20, 2014 at 7:00 PM, Ben Coman <[hidden email] <mailto:[hidden email]>> wrote:
>>>    Eliot Miranda wrote:
>>>        Hi All,
>>>            64-bit Spur can usefully provide an immediate float, a
>>>        61-bit subset of the ieee double precision float.     I wonder if class SmallDouble would be more intention revealing?
>>>    In practice 61 bits will be "more than enough"(tm) for anyone. But I
>>>    can envisage in a business environment environment software needing
>>>    to comply with (sometimes irrelevant) feature checklists, with one
>>>    of those likely being full 64 bit compliant IEEE Doubles.  Can we
>>>    have such a class, to which 61 bit floats are auto-promoted as required?
>>> Just as SmallInteger is seamless with the large integers, so SmallFloat is seamless with boxed Float.  The SmallFloat representation is used where ever possible, since it is faster both to decode (no memory fetch) and to encode (no allocation).  But operations overflow into the boxed representation if outside the SmallFloat range.
>> (btw, rather than SmallFloat and BoxedFloat, I think SmallFloat and LargeFloat would align better with the Integer hierarchy.)
>>
>> So I understand that immediate types will overflow to boxes types :)
>>
>> To try to be more clear, integers don't have a well defined size/format.  It varies with architecture word size.  So SmallInteger and LargeInteger are reasonable descriptions.  But floats have a well defined format defined by IEEE. Since you are pivoting around the IEEE Double format (you define it as "61-bit subset of the ieee double precision float"), rather than generic SmallFloat and LargeFloat, use SmallDouble and LargeDouble. (anyway, maybe I'm off track. Its not a big deal).
>
> Ah, I like this.  Thanks.

Cool. :)

David T. Lewis wrote:
 >
 > I have always felt that the mapping of Float to 64-bit double and
 > FloatArray to 32-bit float is awkward. It may be that 32-bit floats
 > are becoming less relevant nowadays, but if short float values are
 > still important, then it would be nice to be able to represent them
 > directly. I like the idea of having a Float class and a Double class
 > to represent the two most common representations. A class hierarchy
 > that could potentially support this sounds like a good idea to me.
 >
 > I have no experience with VW, but a LimitedPrecisionReal hierachy
 > sounds like a reasonable approach.

You also might also have Single subclassed from abstract Float.

cheers -ben
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: [Vm-dev] [Fwd: Re: [Pharo-dev] Float hierarchy for 64-bit Spur]

Ben Coman
 
Ben Coman wrote:

>
> Eliot Miranda wrote:
>>  
>> Hi Ben,
>>
>> On Nov 20, 2014, at 8:42 PM, Ben Coman <[hidden email]> wrote:
>>
>>> Eliot Miranda wrote:
>>>> On Thu, Nov 20, 2014 at 7:00 PM, Ben Coman <[hidden email]
>>>> <mailto:[hidden email]>> wrote:
>>>>    Eliot Miranda wrote:
>>>>        Hi All,
>>>>            64-bit Spur can usefully provide an immediate float, a
>>>>        61-bit subset of the ieee double precision float.     I
>>>> wonder if class SmallDouble would be more intention revealing?
>>>>    In practice 61 bits will be "more than enough"(tm) for anyone. But I
>>>>    can envisage in a business environment environment software needing
>>>>    to comply with (sometimes irrelevant) feature checklists, with one
>>>>    of those likely being full 64 bit compliant IEEE Doubles.  Can we
>>>>    have such a class, to which 61 bit floats are auto-promoted as
>>>> required?
>>>> Just as SmallInteger is seamless with the large integers, so
>>>> SmallFloat is seamless with boxed Float.  The SmallFloat
>>>> representation is used where ever possible, since it is faster both
>>>> to decode (no memory fetch) and to encode (no allocation).  But
>>>> operations overflow into the boxed representation if outside the
>>>> SmallFloat range.
>>> (btw, rather than SmallFloat and BoxedFloat, I think SmallFloat and
>>> LargeFloat would align better with the Integer hierarchy.)
>>>
>>> So I understand that immediate types will overflow to boxes types :)
>>>
>>> To try to be more clear, integers don't have a well defined
>>> size/format.  It varies with architecture word size.  So SmallInteger
>>> and LargeInteger are reasonable descriptions.  But floats have a well
>>> defined format defined by IEEE. Since you are pivoting around the
>>> IEEE Double format (you define it as "61-bit subset of the ieee
>>> double precision float"), rather than generic SmallFloat and
>>> LargeFloat, use SmallDouble and LargeDouble. (anyway, maybe I'm off
>>> track. Its not a big deal).
>>
>> Ah, I like this.  Thanks.

a random thought on implementation of LargeDouble...
is it worth considering a performance versus space tradeoff...
rather than boxing LargeDouble so that access through a pointer reduces
performance(?), could the value be stored in a second 64bits adjacent to
the first? Or does being 128 bits in total complicate things too much?

cheers -ben
Reply | Threaded
Open this post in threaded view
|

64 bits, boxing, and immediate objects (was: Float hierarchy for 64-bit Spur)

Bert Freudenberg
 
On 21.11.2014, at 08:23, Ben Coman <[hidden email]> wrote:

> a random thought on implementation of LargeDouble...
> is it worth considering a performance versus space tradeoff...
> rather than boxing LargeDouble so that access through a pointer reduces performance(?), could the value be stored in a second 64bits adjacent to the first? Or does being 128 bits in total complicate things too much?

That would require a 128-bit image. We are talking about a 64-bit image here. Please read the FAQ for how a 32/64 bit image relates to a 32/64 bit VM:

        http://squeakvm.org/squeak64/faq.html

Reading it is essential to not be confused about running on a 32-bit vs 64-bit computer, which is actually independent of the question at hand. But to understand what we are talking about, we need to go back to 32 bits first.

The Squeak VM (and Cog and Spur) traditionally use 32 bits to identify an object. When you store a reference to an object into some other object, the VM actually stores a 32 bit word to some place in main memory.

When you use a Float in your code, the VM actually allocates 96 bits somewhere in memory (a 32-bit header for house keeping and 64 bits for the IEEE double) and gives you a 32-bit word back, which is a pointer to that object (we also call that an "oop"). This is called "boxing", it wraps the double inside an object. When you add two floats (say 3.0 + 4.0), the VM actually creates two objects and hands you back their oops (e.g. the two hexadecimal numbers @12345600 and @1ABCDE00). Then to add them, the VM reads 64 bits from the memory addresses 12345604 and 1ABCDE04 (skipping the object header), adds these two doubles, allocates another 96 bits in memory (say @56780000), and writes 64 bits of the result to the address 56780004.

If this sounds expensive to you, that's because it is. It is even more expensive than that because we have just created 3*96 = 288 bits of garbage that needs to be cleaned up later, otherwise we would soon run out of memory if we keep allocating. Since everything in Smalltalk is an object, that is what the VM has to do.

But there is a trick. The VM uses it to avoid all this allocating and memory fetching for the most common operations, namely working with smallish integers, which are used everywhere.

That trick is to hide some data in the oop itself. In the 32 bits of object pointers, the lowest two bits are actually always 0, because objects are always allocated at addresses that are a multiple of 4 (32 bits = 4 bytes). If these are always 0, we don't actually need to store them. But since there is no good way to store just 30 bits, we can also use those two bits for something else.

And we do. The VM currently just uses one bit, the least significant bit (LSB). If the LSB is 0, this is a regular pointer to an object in main memory. If the LSB is 1, then the VM uses the other 31 bits to store an integer. Inside the oop itself, not at some place in memory! It does not need to be allocated, or garbage-collected. It's just there, hidden inside the 32-bit oop.

This makes operations on these "small integers" extremely efficient. To add e.g. 3 and 4, the VM gets the oops @00000007 and @00000009, shifts them 1 bit to get the actual integers (7 >> 1 = 3 and 9 >> 1 = 4), adds them, and shifts it back, sets the LSB, and answers @0000000F. All this happens in CPU registers, no memory access needed, which is why this is so fast. Access to main memory is orders of magnitude slower than register access.

We call that an "immediate object". The Squeak VM currently uses only one kind of immediate objects, although there could be more, since we still have an unused bit. It would be great to speed up floating point operations, too. But there is no way to hide a 64-bit double in a 32 bit oop.

Which brings us to the proposed 64-bit object format. Objects are allocated in chunks of 64 bits = 8 bytes, meaning addresses are multiples of 8, leaving the the 3 lowest bits for identifying immediate objects.

But there still is no way to hide a 64-bit double inside a 64-bit oop, because the VM needs at least 1 bit to distinguish between regular object pointers and immediate objects.

So Eliot is proposing a 61-bit immediate Float which (just like SmallIntegers) the VM can process using register operations only. This will be a major boost for most floating point operations (as long as your values are not larger than 10^38).

Coming back to your question: Yes, going to 128 bits would complicate things considerably ;)

- Bert -


smime.p7s (5K) Download Attachment