Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 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.
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".
- 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.
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.
Thoughts?
On Thu, Nov 20, 2014 at 05:51:42PM -0800, Eliot Miranda wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of
the ieee double precision float. 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.
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".
- 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.
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.
Thoughts?
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.
Dave
On 21.11.2014, at 04:19, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Nov 20, 2014 at 05:51:42PM -0800, Eliot Miranda wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 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.
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".
- 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.
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.
Thoughts?
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.
Dave
I'd suggest BoxedDouble and ImmediateDouble as names for the concrete subclasses (*). Names do mean something. (**)
You're right about the FloatArray confusion. However, note that the IEEE standard calls it single and double. It's only C using "float" to mean "single precision".
I'd name the abstract superclass Float, for readability, and the isFloat test etc. Also: "Float pi" reads a lot nicer than anything else. I don't see the need for having a deep LimitedPrecisionReal - Float - BoxedDouble/ImmediateDouble deep hierarchy now.
If we ever add single-precision floats, we should name them BoxedSingle and ImmediateSingle. At that point we might want a Single superclass and a LimitedPrecisionReal supersuperclass, but we can cross that bridge when we get there.
- Bert -
(*) Since we're not going to see the class names often, we could even spell it out as BoxedDoublePrecisionFloat and ImmediateDoublePrecisionFloat. Only half joking. It would make the relation to the abstract Float very clear.
(**) We could also try to make the names googleable. I was surprised to not get a good hit for "boxed immediate". Only "boxed unboxed" finds it. Maybe there are two better words?
Quoting Bert Freudenberg bert@freudenbergs.de:
On 21.11.2014, at 04:19, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Nov 20, 2014 at 05:51:42PM -0800, Eliot Miranda wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 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.
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".
- 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.
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.
Thoughts?
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.
Dave
I'd suggest BoxedDouble and ImmediateDouble as names for the concrete subclasses (*). Names do mean something. (**)
You're right about the FloatArray confusion. However, note that the IEEE standard calls it single and double. It's only C using "float" to mean "single precision".
I'd name the abstract superclass Float, for readability, and the isFloat test etc. Also: "Float pi" reads a lot nicer than anything else. I don't see the need for having a deep LimitedPrecisionReal - Float - BoxedDouble/ImmediateDouble deep hierarchy now.
If we ever add single-precision floats, we should name them BoxedSingle and ImmediateSingle. At that point we might want a Single superclass and a LimitedPrecisionReal supersuperclass, but we can cross that bridge when we get there.
- Bert -
(*) Since we're not going to see the class names often, we could even spell it out as BoxedDoublePrecisionFloat and ImmediateDoublePrecisionFloat. Only half joking. It would make the relation to the abstract Float very clear.
(**) We could also try to make the names googleable. I was surprised to not get a good hit for "boxed immediate". Only "boxed unboxed" finds it. Maybe there are two better words?
I very much agree with Bert. But I'd suggest SmallDouble instead of ImmediateDouble for consistency with SmallInteger.
Cheers, Juan Vuletich
On 21.11.2014, at 13:29, J. Vuletich (mail lists) juanlists@jvuletich.org wrote:
Quoting Bert Freudenberg bert@freudenbergs.de:
On 21.11.2014, at 04:19, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Nov 20, 2014 at 05:51:42PM -0800, Eliot Miranda wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 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.
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".
- 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.
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.
Thoughts?
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.
Dave
I'd suggest BoxedDouble and ImmediateDouble as names for the concrete subclasses (*). Names do mean something. (**)
You're right about the FloatArray confusion. However, note that the IEEE standard calls it single and double. It's only C using "float" to mean "single precision".
I'd name the abstract superclass Float, for readability, and the isFloat test etc. Also: "Float pi" reads a lot nicer than anything else. I don't see the need for having a deep LimitedPrecisionReal - Float - BoxedDouble/ImmediateDouble deep hierarchy now.
If we ever add single-precision floats, we should name them BoxedSingle and ImmediateSingle. At that point we might want a Single superclass and a LimitedPrecisionReal supersuperclass, but we can cross that bridge when we get there.
- Bert -
(*) Since we're not going to see the class names often, we could even spell it out as BoxedDoublePrecisionFloat and ImmediateDoublePrecisionFloat. Only half joking. It would make the relation to the abstract Float very clear.
(**) We could also try to make the names googleable. I was surprised to not get a good hit for "boxed immediate". Only "boxed unboxed" finds it. Maybe there are two better words?
I very much agree with Bert. But I'd suggest SmallDouble instead of ImmediateDouble for consistency with SmallInteger.
SmallDouble sounds odd. Why not Single?[1] ;)
Best -Tobias
[1] Don't take that too serious
Tobias Pape wrote:
On 21.11.2014, at 13:29, J. Vuletich (mail lists) juanlists@jvuletich.org wrote:
Quoting Bert Freudenberg bert@freudenbergs.de:
On 21.11.2014, at 04:19, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Nov 20, 2014 at 05:51:42PM -0800, Eliot Miranda wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 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.
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".
- 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.
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.
Thoughts?
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.
Dave
I'd suggest BoxedDouble and ImmediateDouble as names for the concrete subclasses (*). Names do mean something. (**)
You're right about the FloatArray confusion. However, note that the IEEE standard calls it single and double. It's only C using "float" to mean "single precision".
I'd name the abstract superclass Float, for readability, and the isFloat test etc. Also: "Float pi" reads a lot nicer than anything else. I don't see the need for having a deep LimitedPrecisionReal - Float - BoxedDouble/ImmediateDouble deep hierarchy now.
If we ever add single-precision floats, we should name them BoxedSingle and ImmediateSingle. At that point we might want a Single superclass and a LimitedPrecisionReal supersuperclass, but we can cross that bridge when we get there.
- Bert -
(*) Since we're not going to see the class names often, we could even spell it out as BoxedDoublePrecisionFloat and ImmediateDoublePrecisionFloat. Only half joking. It would make the relation to the abstract Float very clear.
(**) We could also try to make the names googleable. I was surprised to not get a good hit for "boxed immediate". Only "boxed unboxed" finds it. Maybe there are two better words?
I very much agree with Bert. But I'd suggest SmallDouble instead of ImmediateDouble for consistency with SmallInteger.
SmallDouble sounds odd. Why not Single?[1] ;)
Best -Tobias
[1] Don't take that too serious
Because its not Single!
Maybe better would be MoreThanSingle? Or Married? Or if you don't want to go that far, just Defacto? ;)
Quoting Tobias Pape Das.Linux@gmx.de:
On 21.11.2014, at 13:29, J. Vuletich (mail lists) juanlists@jvuletich.org wrote:
Quoting Bert Freudenberg bert@freudenbergs.de:
On 21.11.2014, at 04:19, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Nov 20, 2014 at 05:51:42PM -0800, Eliot Miranda wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 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.
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".
- 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.
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.
Thoughts?
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.
Dave
I'd suggest BoxedDouble and ImmediateDouble as names for the concrete subclasses (*). Names do mean something. (**)
You're right about the FloatArray confusion. However, note that the IEEE standard calls it single and double. It's only C using "float" to mean "single precision".
I'd name the abstract superclass Float, for readability, and the isFloat test etc. Also: "Float pi" reads a lot nicer than anything else. I don't see the need for having a deep LimitedPrecisionReal
- Float - BoxedDouble/ImmediateDouble deep hierarchy now.
If we ever add single-precision floats, we should name them BoxedSingle and ImmediateSingle. At that point we might want a Single superclass and a LimitedPrecisionReal supersuperclass, but we can cross that bridge when we get there.
- Bert -
(*) Since we're not going to see the class names often, we could even spell it out as BoxedDoublePrecisionFloat and ImmediateDoublePrecisionFloat. Only half joking. It would make the relation to the abstract Float very clear.
(**) We could also try to make the names googleable. I was surprised to not get a good hit for "boxed immediate". Only "boxed unboxed" finds it. Maybe there are two better words?
I very much agree with Bert. But I'd suggest SmallDouble instead of ImmediateDouble for consistency with SmallInteger.
SmallDouble sounds odd. Why not Single?[1] ;)
Best -Tobias
[1] Don't take that too serious
I was taking it serious when I got it :).
Maybe QueenSizeDouble and KingSizeDouble would work?
Cheers, Juan Vuletich
In Pharo the Integer hierarchy is:
Integer LargeInteger LargeNegativeInteger LargePositiveInteger SmallInteger
For consistency l'll suggest:
Float LargeFloat SmallFloat
Now as Float are doubles by opposition to other floating pointers libraries or ScaledDecimal, we may want to use double instead of float. But smalltalkers are used to Float for doubles so I don't really see the point.
Double LargeDouble SmallDouble
If we add instead as suggested:
Float BoxedFloat ImmediateFloat
Are we going to change the Integer class hierarchy to match it like that:
Integer BoxedInteger BoxedNegativeInteger BoxedPositiveInteger ImmediateInteger
?
LargeIntegers are variable sized byte objects that are from 4 bytes to many bytes long so it is more than just a boxed int.
On the other hand, non immediate floats are just boxed doubles. So having BoxedFloat by opposition to LargeFloat to mean that this is just a boxed object may make sense...
But does ImmediateInteger make sense ?
2014-11-21 14:01 GMT+01:00 J. Vuletich (mail lists) <juanlists@jvuletich.org
:
Quoting Tobias Pape Das.Linux@gmx.de:
On 21.11.2014, at 13:29, J. Vuletich (mail lists) <
juanlists@jvuletich.org> wrote:
Quoting Bert Freudenberg bert@freudenbergs.de:
On 21.11.2014, at 04:19, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Nov 20, 2014 at 05:51:42PM -0800, Eliot Miranda wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 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.
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".
- 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.
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.
Thoughts?
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.
Dave
I'd suggest BoxedDouble and ImmediateDouble as names for the concrete subclasses (*). Names do mean something. (**)
You're right about the FloatArray confusion. However, note that the IEEE standard calls it single and double. It's only C using "float" to mean "single precision".
I'd name the abstract superclass Float, for readability, and the isFloat test etc. Also: "Float pi" reads a lot nicer than anything else. I don't see the need for having a deep LimitedPrecisionReal - Float - BoxedDouble/ImmediateDouble deep hierarchy now.
If we ever add single-precision floats, we should name them BoxedSingle and ImmediateSingle. At that point we might want a Single superclass and a LimitedPrecisionReal supersuperclass, but we can cross that bridge when we get there.
- Bert -
(*) Since we're not going to see the class names often, we could even spell it out as BoxedDoublePrecisionFloat and ImmediateDoublePrecisionFloat. Only half joking. It would make the relation to the abstract Float very clear.
(**) We could also try to make the names googleable. I was surprised to not get a good hit for "boxed immediate". Only "boxed unboxed" finds it. Maybe there are two better words?
I very much agree with Bert. But I'd suggest SmallDouble instead of ImmediateDouble for consistency with SmallInteger.
SmallDouble sounds odd. Why not Single?[1] ;)
Best -Tobias
[1] Don't take that too serious
I was taking it serious when I got it :).
Maybe QueenSizeDouble and KingSizeDouble would work?
Cheers, Juan Vuletich
On 21.11.2014, at 13:29, J. Vuletich (mail lists) juanlists@jvuletich.org wrote:
Quoting Bert Freudenberg bert@freudenbergs.de:
I'd suggest BoxedDouble and ImmediateDouble as names for the concrete subclasses (*). Names do mean something. (**)
You're right about the FloatArray confusion. However, note that the IEEE standard calls it single and double. It's only C using "float" to mean "single precision".
I'd name the abstract superclass Float, for readability, and the isFloat test etc. Also: "Float pi" reads a lot nicer than anything else. I don't see the need for having a deep LimitedPrecisionReal - Float - BoxedDouble/ImmediateDouble deep hierarchy now.
If we ever add single-precision floats, we should name them BoxedSingle and ImmediateSingle. At that point we might want a Single superclass and a LimitedPrecisionReal supersuperclass, but we can cross that bridge when we get there.
- Bert -
(*) Since we're not going to see the class names often, we could even spell it out as BoxedDoublePrecisionFloat and ImmediateDoublePrecisionFloat. Only half joking. It would make the relation to the abstract Float very clear.
(**) We could also try to make the names googleable. I was surprised to not get a good hit for "boxed immediate". Only "boxed unboxed" finds it. Maybe there are two better words?
I very much agree with Bert. But I'd suggest SmallDouble instead of ImmediateDouble for consistency with SmallInteger.
Then it would have to be LargeDouble for consistency with LargeInteger, too. Which I don't find compelling.
Also, with the 64 bit format we get many more immediate objects. There already are immediate integers and characters, floats will be the third, there could be more, like immediate points. For those, the small/large distinction does not make sense.
Maybe Eliot's idea of keeping "Float" in the name was best, but instead of "small" use "immediate":
Float - BoxedFloat - ImmediateFloat
A Float is either a BoxedFloat or an ImmediateFloat, depending on the magnitude of its exponent.
- Bert -
Quoting Bert Freudenberg bert@freudenbergs.de:
On 21.11.2014, at 13:29, J. Vuletich (mail lists) juanlists@jvuletich.org wrote:
Quoting Bert Freudenberg bert@freudenbergs.de:
I'd suggest BoxedDouble and ImmediateDouble as names for the concrete subclasses (*). Names do mean something. (**)
You're right about the FloatArray confusion. However, note that the IEEE standard calls it single and double. It's only C using "float" to mean "single precision".
I'd name the abstract superclass Float, for readability, and the isFloat test etc. Also: "Float pi" reads a lot nicer than anything else. I don't see the need for having a deep LimitedPrecisionReal
- Float - BoxedDouble/ImmediateDouble deep hierarchy now.
If we ever add single-precision floats, we should name them BoxedSingle and ImmediateSingle. At that point we might want a Single superclass and a LimitedPrecisionReal supersuperclass, but we can cross that bridge when we get there.
- Bert -
(*) Since we're not going to see the class names often, we could even spell it out as BoxedDoublePrecisionFloat and ImmediateDoublePrecisionFloat. Only half joking. It would make the relation to the abstract Float very clear.
(**) We could also try to make the names googleable. I was surprised to not get a good hit for "boxed immediate". Only "boxed unboxed" finds it. Maybe there are two better words?
I very much agree with Bert. But I'd suggest SmallDouble instead of ImmediateDouble for consistency with SmallInteger.
Then it would have to be LargeDouble for consistency with LargeInteger, too. Which I don't find compelling.
Please no. 'Large' in LargeInteger means unlimited or at least extended range. These won't be 'extended' doubles (like, for example, C 'long double'). They would be plain standard ieee Double. A LargeDouble could perhaps be an arbitrary precision Double or such, some day.
Also, with the 64 bit format we get many more immediate objects. There already are immediate integers and characters, floats will be the third, there could be more, like immediate points. For those, the small/large distinction does not make sense.
That's a point, sure. But the parallels between SmallInteger and SmallDouble should be explicit.
Maybe Eliot's idea of keeping "Float" in the name was best, but instead of "small" use "immediate":
Float - BoxedFloat - ImmediateFloat
A Float is either a BoxedFloat or an ImmediateFloat, depending on the magnitude of its exponent.
- Bert -
Again, please no. Float means 32 bit single precision for too many people out there. It means that in our own FloatArrays. Doubles are Doubles.
To me the best option is SmallDouble and BoxedDouble or simply Double.
Cheers, Juan Vuletich
To be abstract, or to be concrete, that is the question.
Coming back to Eliot's proposal:
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. [...] An alternative [...] 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.
Float | +------- BoxedFloat | +------- SmallFloat
LimitedPrecisionReal | +------- Float | +------- SmallFloat
The actual question was if the class named "Float" (as used in expressions like "Float pi") should be concrete or abstract.
I strongly agree with Eliot's assessment that making Float the abstract superclass is best. What we name the two concrete subclasses is bikeshedding, and I trust Eliot to pick something not too unreasonable.
- Bert -
On Fri, Nov 21, 2014 at 5:30 AM, Bert Freudenberg bert@freudenbergs.de wrote:
To be abstract, or to be concrete, that is the question.
Coming back to Eliot's proposal:
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.
[...] An alternative [...] 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.
Float | +------- BoxedFloat | +------- SmallFloat
LimitedPrecisionReal | +------- Float | +------- SmallFloat
The actual question was if the class named "Float" (as used in expressions like "Float pi") should be concrete or abstract.
I strongly agree with Eliot's assessment that making Float the abstract superclass is best. What we name the two concrete subclasses is bikeshedding, and I trust Eliot to pick something not too unreasonable.
Good. I think I'll go with
Float | +------- BoxedDouble | +------- SmallDouble
ImmediateDouble is fine too, but I like the symmetry with SmallInteger.
"Float" is also the name of an IEEE entity in a multitude of languages other than ours... if we needed to implement single precision floating point numbers, generally called "float", where would that fit?
On 11/21/14 10:08 , Eliot Miranda wrote:
Good. I think I'll go with
Float | +------- BoxedDouble | +------- SmallDouble
On 28.11.2014, at 01:24, Andres Valloud avalloud@smalltalk.comcastbiz.net wrote:
"Float" is also the name of an IEEE entity in a multitude of languages other than ours... if we needed to implement single precision floating point numbers, generally called "float", where would that fit?
On 11/21/14 10:08 , Eliot Miranda wrote:
Good. I think I'll go with
Float | +------- BoxedDouble | +------- SmallDouble
Hi Andres,
you missed the decision: We're going with BoxedFloat64 and SmallFloat64 now.
- Bert -
On Fri, Nov 21, 2014 at 02:30:59PM +0100, Bert Freudenberg wrote:
To be abstract, or to be concrete, that is the question.
Coming back to Eliot's proposal:
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. [...] An alternative [...] 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.
Float | +------- BoxedFloat | +------- SmallFloat
LimitedPrecisionReal | +------- Float | +------- SmallFloat
The actual question was if the class named "Float" (as used in expressions like "Float pi") should be concrete or abstract.
I strongly agree with Eliot's assessment that making Float the abstract superclass is best. What we name the two concrete subclasses is bikeshedding, and I trust Eliot to pick something not too unreasonable.
I also agree. The name "Float" suggests the concept of floating point arithmetic. There are many different ways to implement that concept (*). But for all of the possible concrete implementations of floating point numbers, the name "Float" makes sense in the abstract.
In Squeak, all instances of "Float" (in the abstract sense) are currently implemented as 64-bit doubles (instances of class Float) or 32-bit singles (hidden within FloatArray). Spur-64 will provide an immediate implementation. Maybe somebody will come up with a class to represent the 32-bit floating point values in a FloatArray. And maybe someone else will come up with a 128 bit floating point represention, or something else entirely. But in any case, it seems natural to have an abstract "Float" to represent all of the concrete implementations that may prove necessary or useful over time.
So +1 for making Float be the abstract superclass.
Dave
(*) As a former field service engineer for Harris Computer Systems, I still consider the 48-bit floating point format of the H800 series to be superior to the awkward compromises of 32-bit and 64-bit floating point representations ;-) See pages 2-2 and 6-1 of the manual for descriptions of the floating point data formats (I think I have a paper copy of this moldering away in my basement).
http://bitsavers.informatik.uni-stuttgart.de/pdf/harris/0830007-000_Series_8...
On 24.11.2014, at 05:09, David T. Lewis lewis@mail.msen.com wrote:
(*) As a former field service engineer for Harris Computer Systems, I still consider the 48-bit floating point format of the H800 series to be superior to the awkward compromises of 32-bit and 64-bit floating point representations ;-) See pages 2-2 and 6-1 of the manual for descriptions of the floating point data formats (I think I have a paper copy of this moldering away in my basement).
http://bitsavers.informatik.uni-stuttgart.de/pdf/harris/0830007-000_Series_8...
Oh, I got excited for a moment there, thinking that maybe this could be the origin of Smalltalk-78's weird 48 bit floating point format. But it's completely different. I had to reverse-engineer it because Dan could not remember (only later we got a printout of the VM's 8086 assembly source code). It's optimized for a software implementation with the mantissa on a 16-bit word boundary. Not sure why the exponent's sign bit is in the LSB though. But 16 bits of exponent, can you imagine the range? Luckily there were no insanely large instances in the snapshot. They get converted to modern floats when parsing the original object space dump:
wordsAsFloat: function() { // layout of NoteTaker Floats (from MSB): // 15 bits exponent in two's complement without bias, 1 bit sign // 32 bits mantissa including its highest bit (which is implicit in IEEE 754) if (this.words[1] == 0) return 0.0; // if high-bit of mantissa is 0, then it's all zero var nt0 = this.words[0], nt1 = this.words[1], nt2 = this.words[2], ntExponent = nt0 >> 1, ntSign = nt0 & 1, ntMantissa = (nt1 & 0x7FFF) << 16 | nt2, // drop high bit of mantissa ieeeExponent = (ntExponent + 1022) & 0x7FF, // IEEE: 11 bit exponent, biased ieee = new DataView(new ArrayBuffer(8)); // IEEE is 1 sign bit, 11 bits exponent, 53 bits mantissa omitting the highest bit (which is always 1, except for 0.0) ieee.setInt32(0, ntSign << 31 | ieeeExponent << (31-11) | ntMantissa >> 11); // 20 bits of ntMantissa ieee.setInt32(4, ntMantissa << (32-11)); // remaining 11 bits of ntMantissa, rest filled up with 0 // why not use setInt64()? Because JavaScript does not have 64 bit ints return ieee.getFloat64(0); }
- Bert -
On Mon, Nov 24, 2014 at 11:51:06AM +0100, Bert Freudenberg wrote:
On 24.11.2014, at 05:09, David T. Lewis lewis@mail.msen.com wrote:
(*) As a former field service engineer for Harris Computer Systems, I
still
consider the 48-bit floating point format of the H800 series to be
superior to
the awkward compromises of 32-bit and 64-bit floating point
representations ;-)
See pages 2-2 and 6-1 of the manual for descriptions of the floating
point data
formats (I think I have a paper copy of this moldering away in my
basement).
http://bitsavers.informatik.uni-stuttgart.de/pdf/harris/0830007-000_Series_8...
Oh, I got excited for a moment there, thinking that maybe this could be the origin of Smalltalk-78's weird 48 bit floating point format. But it's completely different.
It's just a coincidence I'm sure. A 48 bit float makes a lot of sense. Minicomputers were typically 16 bit machines, but the H800 was a 24 bit machine with 48 and 96 bit floating point data types and 24 bit registers. 24 bits was a lot of address space, and a 48 bit float was far superior to a 32 bits for scientific and numeric computing. In those days, "Super Minicomputer" was a market category, and the H800 was marketed that way, targeting applications such as finite element analysis.
I would not be surprised if 16 bit Smalltalk systems arrived at similar conclusions for general purpose floating point representation. 32 bits would have been too small, and 64 bits too big. 48 bits was just about the right size to be useful for serious work on a small machine.
Very large mantissa ranges also make sense for interative numeric work, where I expect that they would reduce the need to keep track of numeric overflow in some kinds of calculations (just guessing, but I'm sure that was the reason).
I had to reverse-engineer it because Dan could not remember (only later we got a printout of the VM's 8086 assembly source code). It's optimized for a software implementation with the mantissa on a 16-bit word boundary. Not sure why the exponent's sign bit is in the LSB though. But 16 bits of exponent, can you imagine the range? Luckily there were no insanely large instances in the snapshot. They get converted to modern floats when parsing the original object space dump:
wordsAsFloat: function() { // layout of NoteTaker Floats (from MSB): // 15 bits exponent in two's complement without bias, 1 bit sign // 32 bits mantissa including its highest bit (which is implicit
in IEEE 754)
if (this.words[1] == 0) return 0.0; // if high-bit of mantissa
is 0, then it's all zero
var nt0 = this.words[0], nt1 = this.words[1], nt2 = this.words[2], ntExponent = nt0 >> 1, ntSign = nt0 & 1, ntMantissa = (nt1 &
0x7FFF) << 16 | nt2, // drop high bit of mantissa
ieeeExponent = (ntExponent + 1022) & 0x7FF, // IEEE: 11 bit
exponent, biased
ieee = new DataView(new ArrayBuffer(8)); // IEEE is 1 sign bit, 11 bits exponent, 53 bits mantissa
omitting the highest bit (which is always 1, except for 0.0)
ieee.setInt32(0, ntSign << 31 | ieeeExponent << (31-11) |
ntMantissa >> 11); // 20 bits of ntMantissa
ieee.setInt32(4, ntMantissa << (32-11)); // remaining 11 bits of
ntMantissa, rest filled up with 0
// why not use setInt64()? Because JavaScript does not have 64
bit ints
return ieee.getFloat64(0); }
Cool! I had no idea that you were dialing your wayback machine this far back in time. Very impressive indeed.
Dave
Bert Freudenberg wrote:
On 21.11.2014, at 04:19, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Nov 20, 2014 at 05:51:42PM -0800, Eliot Miranda wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 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.
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".
- 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.
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.
Thoughts?
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.
Dave
I'd suggest BoxedDouble and ImmediateDouble as names for the concrete subclasses (*). Names do mean something. (**)
This is a nice idea, except we have the legacy of SmallInteger and LargeInteger, and I don't like the inconsistency of Float not following the same rule. The boxing/unboxing can be covered in the class comment. Unless you want to change to BoxedInteger and ImmediateInteger ?
cheers -ben
You're right about the FloatArray confusion. However, note that the IEEE standard calls it single and double. It's only C using "float" to mean "single precision".
I'd name the abstract superclass Float, for readability, and the isFloat test etc. Also: "Float pi" reads a lot nicer than anything else. I don't see the need for having a deep LimitedPrecisionReal - Float - BoxedDouble/ImmediateDouble deep hierarchy now.
If we ever add single-precision floats, we should name them BoxedSingle and ImmediateSingle. At that point we might want a Single superclass and a LimitedPrecisionReal supersuperclass, but we can cross that bridge when we get there.
- Bert -
(*) Since we're not going to see the class names often, we could even spell it out as BoxedDoublePrecisionFloat and ImmediateDoublePrecisionFloat. Only half joking. It would make the relation to the abstract Float very clear.
(**) We could also try to make the names googleable. I was surprised to not get a good hit for "boxed immediate". Only "boxed unboxed" finds it. Maybe there are two better words?
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
From the sense that a lot of computing is addressing fuzzy pattern
matching, 32-bit speed and space are actually becoming more relevant.
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.
Dave
On 21.11.2014, at 02:51, Eliot Miranda eliot.miranda@gmail.com wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. 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.
This is worded confusingly. It sounds like the mantissa has 3 bits less, which would make it less precise.
Here is how I understood it: The mantissa is stored with its full 52 bits of precision (*). But only the lower 8 bits of the 11-bit exponent are stored. If the upper 3 bits of the exponent are needed, then a boxed float is created.
I guess I know what you meant, that it is the 3 lowest significant bits in an oop which are used for tagging immediate objects, and in an IEEE double that is part of the mantissa. But these 3 bits are not lost, but moved elsewhere (namely where the 3 highest significant bits of the exponent used to be stored).
Did I understand correctly? You haven't pushed the code yet so I couldn't verify.
- Bert -
(*) http://en.wikipedia.org/wiki/Double-precision_floating-point_format
On Fri, Nov 21, 2014 at 4:47 AM, Bert Freudenberg bert@freudenbergs.de wrote:
On 21.11.2014, at 02:51, Eliot Miranda eliot.miranda@gmail.com wrote:
Hi All,
64-bit Spur can usefully provide an immediate float, a 61-bit subset
of the ieee double precision float. 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.
This is worded confusingly. It sounds like the mantissa has 3 bits less, which would make it less precise.
It's not worded confusingly, it's just plain wrong :-/. Let me try again...
64-bit Spur can usefully provide an immediate float, a 61-bit subset of the ieee double precision float. The scheme steals 3 bits from the exponent 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.
Here's the representation:
[8 bit exponent][52 bit mantissa][1 bit sign][3 bit tag]
This has the advantage that +/- zero are the only immediate float values that are less than or equal to fifteen. So to convert to a float:
- shift away tags [000][8 bit exponent][52 bit mantissa][1 bit sign]
- if > 1 (i.e. non-zero) add exponent offset: [11 bit exponent][52 bit mantissa][sign bit]
- rotate by -1 [sign bit][11 bit exponent][52 bit mantissa]
And to encode:
- rotate by 1 [11 bit exponent][52 bit mantissa][sign bit]
- if > 1 subtract exponent offset fail if <= 0 test against max value, fail if too big
- shift by 3 and add tag bits: [8 bit exponent][52 bit mantissa][1 bit sign][3 bit tag]
Here is how I understood it: The mantissa is stored with its full 52 bits
of precision (*). But only the lower 8 bits of the 11-bit exponent are stored. If the upper 3 bits of the exponent are needed, then a boxed float is created.
I guess I know what you meant, that it is the 3 lowest significant bits in
an oop which are used for tagging immediate objects, and in an IEEE double that is part of the mantissa. But these 3 bits are not lost, but moved elsewhere (namely where the 3 highest significant bits of the exponent used to be stored).
Did I understand correctly? You haven't pushed the code yet so I couldn't verify.
Yes, of course :-)
- Bert -
(*) http://en.wikipedia.org/wiki/Double-precision_floating-point_format
vm-dev@lists.squeakfoundation.org