Re: [polyml] PackReal32

2021-04-27 Thread David Matthews

Hi Chris,
Thanks for pointing this out.  I've committed a fix that looks like it 
works.  It would be really helpful to have some tests for structures 
such as these that could be included in the test suite.  Actually, 
generally more tests would be welcome; most of those that are there are 
regression tests after bug fixes.


David

On 25/04/2021 11:37, Chris Cannam wrote:

Harking back to this, I've belatedly noticed that the tagged versions of 
subVec, subArr, and update all take the supplied index and use it directly in 
the Word8 array, when they should be multiplying it by bytesPerElem. The 
double-precision and boxed versions have this right, but as it stands the 
tagged version is only capable of retrieving or updating the first value in the 
array correctly.

Multiplying i by bytesPerElem in each case fixes this, i.e. doing something 
like this in all six of the tagged functions:

  fun update(v, i, r) =
  let
  val w: word = r32AsWord r
+val i = i * bytesPerElem
  open Word8Array

... but I notice the double/boxed version has some more logic to check the int 
is within range, so perhaps there is a more appropriate fix.


Chris
___
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml


___
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml


Re: [polyml] PackReal32

2021-02-22 Thread Chris Cannam
No problem, glad to be helpful - especially since I'm the one who asked for the 
feature!

I also have the habit of viewing floating point as black magic, especially 
because of historical issues such as x87 intermediate precision and weird 
things like denormal numbers. So it's quite satisfying to go through a few test 
cases, figure out what the proper representation should be, and see that in 
this situation it's not in fact all that complicated.

Thank you for implementing this and putting it to rights.


Chris

On Mon, 22 Feb 2021, at 07:31, David Matthews wrote:
> Thank you for looking at this.  You're quite right that the shifts were 
> wrong.  I've pushed a fix for this that seems to have corrected it.  I'm 
> not that familiar with the intricacies of floating point numbers so I'm 
> always glad when someone points out problems.
> 
> David
> 
> On 21/02/2021 13:50, Chris Cannam wrote:
> > I took another little look at the behaviour here.
> > 
> > My basic assumption is that, for any Real32.real r,
> > 
> > Real32.== (PackReal32Big.fromBytes (PackReal32Big.toBytes r), r)
> > 
> > should hold. (and the same for Little obviously)
> > 
> > With the current repo code, it's possible to construct values for which 
> > this is not true - if you apply fromBytes to something with the 
> > lowest-order bit set, and then take Real32.nextAfter, you get a value that 
> > "should" have one more bit set than is preserved through this 
> > transformation. The value 1.60916 is an example:
> > 
> >> val r : Real32.real = 1.60916;
> > val r = 1.60916: Real32.real
> >> PackReal32Big.toBytes r;
> > val it = fromList[0wx1F, 0wxC0, 0wx0, 0wxFF]: Word8Vector.vector
> >> PackReal32Big.fromBytes (PackReal32Big.toBytes r);
> > val it = 1.60797: PackReal32Big.real
> >> Real32.== (PackReal32Big.fromBytes (PackReal32Big.toBytes r), r);
> > val it = false: bool
> > 
> > Note the result has been rounded down by 2^-23, which makes sense since the 
> > IEEE 754 fraction part is 23 bits.
> > 
> > I experimentally went into PackReal32Tagged, subtracted 1 from all the 
> > shift constants (the 56, 48, 40, 32), and rebuilt. With this change:
> > 
> >> val r : Real32.real = 1.60916;
> > val r = 1.60916: Real32.real
> >> PackReal32Big.toBytes r;
> > val it = fromList[0wx3F, 0wx80, 0wx1, 0wxFF]: Word8Vector.vector
> >> Real32.== (PackReal32Big.fromBytes (PackReal32Big.toBytes r), r);
> > val it = true: bool
> > 
> > Also now
> > 
> >> PackReal32Big.toBytes 1.0;
> > val it = fromList[0wx3F, 0wx80, 0wx0, 0wx0]: Word8Vector.vector
> > 
> > which is the expected result I mentioned in the previous email.
> > 
> > I'm imagining all this has something to do with the tag bit, but I don't 
> > really know.
> > 
> > 
> > Chris
> > 
> > On Sun, 7 Feb 2021, at 18:06, Chris Cannam wrote:
> >> Oh, thank you!
> >>
> >> I had thought that the difference between x87 and SSE, and the
> >> different internal precisions, mattered only for intermediate register
> >> values during calculation - and that when a 32-bit float was "at rest",
> >> i.e. being stored in 32 bits, it would always have IEEE 754
> >> representation (as described e.g. at
> >> https://en.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:_binary32)
> >>
> >> Is this not right? Do I have the wrong mental model here?
> >>
> >> The current behaviour does indeed seem a bit off (Poly/ML rev
> >> 62a56474f0, 64-bit Linux).
> >>
> >> If I take, say, 1.0 and convert it to bytes big-endian, I think I expect 
> >> to see
> >>
> >> sign bit: 0
> >> exponent (8 bits): 127 (exponent is 0, stored unsigned with an offset of 
> >> 127)
> >> fraction (23 bits): 0 (as the 1 in 1.0 x 2^0 is implicit)
> >>
> >> so 0111  1000      or 3F 80 00 00
> >>
> >> and that's what PackReal32Big.toBytes 1.0 returns in MLton. In Poly/ML
> >> I'm getting this
> >>
> >>> PackReal32Big.toBytes 1.0;
> >> val it = fromList[0wx1F, 0wxC0, 0wx0, 0wx0]: Word8Vector.vector
> >>
> >> 1F C0 00 00 is the same bit pattern as 3F 80 00 00, but shifted right
> >> by one bit, and no longer a normal IEEE 754 number I think. Is it
> >> possible there's an off-by-one error in the bit lookup, or is this all
> >> a symptom of my having the wrong idea about what's going on?
> >>
> >> Thanks,
> >>
> >>
> >> Chris
> >>
> >> On Sat, 6 Feb 2021, at 16:24, David Matthews wrote:
> >>> I've added this to master.  It seemed like a good idea although it was a
> >>> bit more complicated than PackReal because Real32.real values are
> >>> "boxed" in 32-bit Poly/ML but tagged in 64-bit.
> >>>
> >>> I'm not exactly clear how useful PackRealN operations are for general
> >>> data interchange.  Currently they just store and load the bytes that
> >>> make up the number but how those are interpreted will depend on the
> >>> platform.  For example it seems that the X87 format used on X86/32 is
> >>> different from the SSE format used on X86/64.
> >>>
> >>> 

Re: [polyml] PackReal32

2021-02-21 Thread David Matthews
Thank you for looking at this.  You're quite right that the shifts were 
wrong.  I've pushed a fix for this that seems to have corrected it.  I'm 
not that familiar with the intricacies of floating point numbers so I'm 
always glad when someone points out problems.


David

On 21/02/2021 13:50, Chris Cannam wrote:

I took another little look at the behaviour here.

My basic assumption is that, for any Real32.real r,

Real32.== (PackReal32Big.fromBytes (PackReal32Big.toBytes r), r)

should hold. (and the same for Little obviously)

With the current repo code, it's possible to construct values for which this is not true 
- if you apply fromBytes to something with the lowest-order bit set, and then take 
Real32.nextAfter, you get a value that "should" have one more bit set than is 
preserved through this transformation. The value 1.60916 is an example:


val r : Real32.real = 1.60916;

val r = 1.60916: Real32.real

PackReal32Big.toBytes r;

val it = fromList[0wx1F, 0wxC0, 0wx0, 0wxFF]: Word8Vector.vector

PackReal32Big.fromBytes (PackReal32Big.toBytes r);

val it = 1.60797: PackReal32Big.real

Real32.== (PackReal32Big.fromBytes (PackReal32Big.toBytes r), r);

val it = false: bool

Note the result has been rounded down by 2^-23, which makes sense since the 
IEEE 754 fraction part is 23 bits.

I experimentally went into PackReal32Tagged, subtracted 1 from all the shift 
constants (the 56, 48, 40, 32), and rebuilt. With this change:


val r : Real32.real = 1.60916;

val r = 1.60916: Real32.real

PackReal32Big.toBytes r;

val it = fromList[0wx3F, 0wx80, 0wx1, 0wxFF]: Word8Vector.vector

Real32.== (PackReal32Big.fromBytes (PackReal32Big.toBytes r), r);

val it = true: bool

Also now


PackReal32Big.toBytes 1.0;

val it = fromList[0wx3F, 0wx80, 0wx0, 0wx0]: Word8Vector.vector

which is the expected result I mentioned in the previous email.

I'm imagining all this has something to do with the tag bit, but I don't really 
know.


Chris

On Sun, 7 Feb 2021, at 18:06, Chris Cannam wrote:

Oh, thank you!

I had thought that the difference between x87 and SSE, and the
different internal precisions, mattered only for intermediate register
values during calculation - and that when a 32-bit float was "at rest",
i.e. being stored in 32 bits, it would always have IEEE 754
representation (as described e.g. at
https://en.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:_binary32)

Is this not right? Do I have the wrong mental model here?

The current behaviour does indeed seem a bit off (Poly/ML rev
62a56474f0, 64-bit Linux).

If I take, say, 1.0 and convert it to bytes big-endian, I think I expect to see

sign bit: 0
exponent (8 bits): 127 (exponent is 0, stored unsigned with an offset of 127)
fraction (23 bits): 0 (as the 1 in 1.0 x 2^0 is implicit)

so 0111  1000      or 3F 80 00 00

and that's what PackReal32Big.toBytes 1.0 returns in MLton. In Poly/ML
I'm getting this


PackReal32Big.toBytes 1.0;

val it = fromList[0wx1F, 0wxC0, 0wx0, 0wx0]: Word8Vector.vector

1F C0 00 00 is the same bit pattern as 3F 80 00 00, but shifted right
by one bit, and no longer a normal IEEE 754 number I think. Is it
possible there's an off-by-one error in the bit lookup, or is this all
a symptom of my having the wrong idea about what's going on?

Thanks,


Chris

On Sat, 6 Feb 2021, at 16:24, David Matthews wrote:

I've added this to master.  It seemed like a good idea although it was a
bit more complicated than PackReal because Real32.real values are
"boxed" in 32-bit Poly/ML but tagged in 64-bit.

I'm not exactly clear how useful PackRealN operations are for general
data interchange.  Currently they just store and load the bytes that
make up the number but how those are interpreted will depend on the
platform.  For example it seems that the X87 format used on X86/32 is
different from the SSE format used on X86/64.

David

On 02/02/2021 09:25, Chris Cannam wrote:

Hello! I find I could do with the PackReal32{Big,Little} structures, 32-bit 
floats being often more amenable to serialisation and used in some storage 
formats.

Would there be any appetite for adding these?

Thanks,


Chris
___
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml




___
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml


Re: [polyml] PackReal32

2021-02-21 Thread Chris Cannam
I took another little look at the behaviour here.

My basic assumption is that, for any Real32.real r,

Real32.== (PackReal32Big.fromBytes (PackReal32Big.toBytes r), r)

should hold. (and the same for Little obviously)

With the current repo code, it's possible to construct values for which this is 
not true - if you apply fromBytes to something with the lowest-order bit set, 
and then take Real32.nextAfter, you get a value that "should" have one more bit 
set than is preserved through this transformation. The value 1.60916 is an 
example:

> val r : Real32.real = 1.60916;
val r = 1.60916: Real32.real
> PackReal32Big.toBytes r;
val it = fromList[0wx1F, 0wxC0, 0wx0, 0wxFF]: Word8Vector.vector
> PackReal32Big.fromBytes (PackReal32Big.toBytes r);
val it = 1.60797: PackReal32Big.real
> Real32.== (PackReal32Big.fromBytes (PackReal32Big.toBytes r), r);
val it = false: bool

Note the result has been rounded down by 2^-23, which makes sense since the 
IEEE 754 fraction part is 23 bits. 

I experimentally went into PackReal32Tagged, subtracted 1 from all the shift 
constants (the 56, 48, 40, 32), and rebuilt. With this change:

> val r : Real32.real = 1.60916;
val r = 1.60916: Real32.real
> PackReal32Big.toBytes r;
val it = fromList[0wx3F, 0wx80, 0wx1, 0wxFF]: Word8Vector.vector
> Real32.== (PackReal32Big.fromBytes (PackReal32Big.toBytes r), r);
val it = true: bool

Also now

> PackReal32Big.toBytes 1.0;
val it = fromList[0wx3F, 0wx80, 0wx0, 0wx0]: Word8Vector.vector

which is the expected result I mentioned in the previous email.

I'm imagining all this has something to do with the tag bit, but I don't really 
know.


Chris

On Sun, 7 Feb 2021, at 18:06, Chris Cannam wrote:
> Oh, thank you!
> 
> I had thought that the difference between x87 and SSE, and the 
> different internal precisions, mattered only for intermediate register 
> values during calculation - and that when a 32-bit float was "at rest", 
> i.e. being stored in 32 bits, it would always have IEEE 754 
> representation (as described e.g. at 
> https://en.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:_binary32)
> 
> Is this not right? Do I have the wrong mental model here?
> 
> The current behaviour does indeed seem a bit off (Poly/ML rev 
> 62a56474f0, 64-bit Linux).
> 
> If I take, say, 1.0 and convert it to bytes big-endian, I think I expect to 
> see
> 
> sign bit: 0
> exponent (8 bits): 127 (exponent is 0, stored unsigned with an offset of 127)
> fraction (23 bits): 0 (as the 1 in 1.0 x 2^0 is implicit)
> 
> so 0111  1000      or 3F 80 00 00 
> 
> and that's what PackReal32Big.toBytes 1.0 returns in MLton. In Poly/ML 
> I'm getting this
> 
> > PackReal32Big.toBytes 1.0;
> val it = fromList[0wx1F, 0wxC0, 0wx0, 0wx0]: Word8Vector.vector
> 
> 1F C0 00 00 is the same bit pattern as 3F 80 00 00, but shifted right 
> by one bit, and no longer a normal IEEE 754 number I think. Is it 
> possible there's an off-by-one error in the bit lookup, or is this all 
> a symptom of my having the wrong idea about what's going on?
> 
> Thanks,
> 
> 
> Chris
> 
> On Sat, 6 Feb 2021, at 16:24, David Matthews wrote:
> > I've added this to master.  It seemed like a good idea although it was a 
> > bit more complicated than PackReal because Real32.real values are 
> > "boxed" in 32-bit Poly/ML but tagged in 64-bit.
> > 
> > I'm not exactly clear how useful PackRealN operations are for general 
> > data interchange.  Currently they just store and load the bytes that 
> > make up the number but how those are interpreted will depend on the 
> > platform.  For example it seems that the X87 format used on X86/32 is 
> > different from the SSE format used on X86/64.
> > 
> > David
> > 
> > On 02/02/2021 09:25, Chris Cannam wrote:
> > > Hello! I find I could do with the PackReal32{Big,Little} structures, 
> > > 32-bit floats being often more amenable to serialisation and used in some 
> > > storage formats.
> > > 
> > > Would there be any appetite for adding these?
> > > 
> > > Thanks,
> > > 
> > > 
> > > Chris
> > > ___
> > > polyml mailing list
> > > polyml@inf.ed.ac.uk
> > > http://lists.inf.ed.ac.uk/mailman/listinfo/polyml
> > > 
> >
___
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml


Re: [polyml] PackReal32

2021-02-07 Thread Chris Cannam
Oh, thank you!

I had thought that the difference between x87 and SSE, and the different 
internal precisions, mattered only for intermediate register values during 
calculation - and that when a 32-bit float was "at rest", i.e. being stored in 
32 bits, it would always have IEEE 754 representation (as described e.g. at 
https://en.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:_binary32)

Is this not right? Do I have the wrong mental model here?

The current behaviour does indeed seem a bit off (Poly/ML rev 62a56474f0, 
64-bit Linux).

If I take, say, 1.0 and convert it to bytes big-endian, I think I expect to see

sign bit: 0
exponent (8 bits): 127 (exponent is 0, stored unsigned with an offset of 127)
fraction (23 bits): 0 (as the 1 in 1.0 x 2^0 is implicit)

so 0111  1000      or 3F 80 00 00 

and that's what PackReal32Big.toBytes 1.0 returns in MLton. In Poly/ML I'm 
getting this

> PackReal32Big.toBytes 1.0;
val it = fromList[0wx1F, 0wxC0, 0wx0, 0wx0]: Word8Vector.vector

1F C0 00 00 is the same bit pattern as 3F 80 00 00, but shifted right by one 
bit, and no longer a normal IEEE 754 number I think. Is it possible there's an 
off-by-one error in the bit lookup, or is this all a symptom of my having the 
wrong idea about what's going on?

Thanks,


Chris

On Sat, 6 Feb 2021, at 16:24, David Matthews wrote:
> I've added this to master.  It seemed like a good idea although it was a 
> bit more complicated than PackReal because Real32.real values are 
> "boxed" in 32-bit Poly/ML but tagged in 64-bit.
> 
> I'm not exactly clear how useful PackRealN operations are for general 
> data interchange.  Currently they just store and load the bytes that 
> make up the number but how those are interpreted will depend on the 
> platform.  For example it seems that the X87 format used on X86/32 is 
> different from the SSE format used on X86/64.
> 
> David
> 
> On 02/02/2021 09:25, Chris Cannam wrote:
> > Hello! I find I could do with the PackReal32{Big,Little} structures, 32-bit 
> > floats being often more amenable to serialisation and used in some storage 
> > formats.
> > 
> > Would there be any appetite for adding these?
> > 
> > Thanks,
> > 
> > 
> > Chris
> > ___
> > polyml mailing list
> > polyml@inf.ed.ac.uk
> > http://lists.inf.ed.ac.uk/mailman/listinfo/polyml
> > 
>
___
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml


Re: [polyml] PackReal32

2021-02-06 Thread David Matthews
I've added this to master.  It seemed like a good idea although it was a 
bit more complicated than PackReal because Real32.real values are 
"boxed" in 32-bit Poly/ML but tagged in 64-bit.


I'm not exactly clear how useful PackRealN operations are for general 
data interchange.  Currently they just store and load the bytes that 
make up the number but how those are interpreted will depend on the 
platform.  For example it seems that the X87 format used on X86/32 is 
different from the SSE format used on X86/64.


David

On 02/02/2021 09:25, Chris Cannam wrote:

Hello! I find I could do with the PackReal32{Big,Little} structures, 32-bit 
floats being often more amenable to serialisation and used in some storage 
formats.

Would there be any appetite for adding these?

Thanks,


Chris
___
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml


___
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml