[squeak-dev] ASN.1 Floats

Alan Pinch alan.c.pinch at gmail.com
Thu Oct 12 22:01:06 UTC 2017

```Thanks for the info, this gives me a good start. I started working on
the encoding, as the reading is more complex. I'll defer on
understanding the Cuis code and get it to work right, as you said.

On 10/12/2017 03:21 PM, Nicolas Cellier wrote:
>
>
> 2017-10-12 17:46 GMT+02:00 Bert Freudenberg <bert at freudenbergs.de
> <mailto:bert at freudenbergs.de>>:
>
>     On Thu, Oct 12, 2017 at 11:36 AM, Alan Pinch
>     <alan.c.pinch at gmail.com <mailto:alan.c.pinch at gmail.com>>wrote:
>
>         The same issue exists in ASN1 support, none for float type tag
>         9. I would love to add this support but I am unsure how to
>         breakdown a float into mantissa, base and exponent. Here is a
>         description of how ASN1 formats a REAL into the stream of bytes:
>
>             Type REAL takes values that are the machine representation
>             of a real number, namely the triplet (m, b, e), where m is
>             the mantissa (a signed number), b the base (2 or 10), and
>             e the exponent (a signed number). For example, the
>             representation of the value 3.14 for the variable Pi,
>             declared as Pi ::= REAL, can be (314, 10, -2). Three
>             special values, PLUS-INFINITY, 0, and MINUS-INFINITY, are
>             also allowed.
>
>         Here are some sample values:
>
>               * 09 00 = 0 (zero)
>               * 09 01 40 = +INF (infinity)
>               * 09 01 41 = -INF
>               * 09 08 03 2b 31 2e 30 65 2b 30 = "+1.0e+0" = 1.0 (exact
>                 decimal)
>               * 09 05 80 fe 55 55 55 = 1398101.25 (binary, 0x555555 *
>                 2^-2)
>               * 09 06 83 00 fc 00 00 01 = 0.0625 (binary, 0x000001 * 2^-4)
>
>         I have not parsed out these samples into these components so
>         it's greek.
>
>
>     ​Well it's not the same issue as ​ASN.1 float representation is
>     different from IEEE 754 format. To convert a Squeak Float into an
>     IEEE 64 bit pattern we simply access its underlying
>     representation, because the VM uses IEEE internally.
>
>     It sounds like ASN.1 stores mantissa, base, and exponent
>     separately. IEEE calls the mantissa "significand" and that's the
>     name of the corresponding Squeak method. The exponent is called
>     "exponent", and the base is implicitly 2:
>
>     1398101.25 significand
>     => 1.3333332538604736
>     1398101.25 exponent
>     => 20
>     1.3333332538604736 timesTwoPower: 20
>     => 1.39810125e6
>     1398101.25 = 1.39810125e6
>     => true
>
>     The IEEE significand/mantissa is normalized to a fractional number
>     1 <= m < 2. ASN wants integral numbers, so you could convert it to
>     an integer like this:
>
>     x := 1398101.25.
>     mantissa := x significand.
>     exponent := x exponent.
>     base := 2.
>     [mantissa fractionPart isZero] whileFalse:
>     [mantissa := mantissa * base.
>     exponent := exponent - 1].
>     {mantissa asInteger hex. base. exponent}
>      #('16r555555' 2 -2)
>
>     ... which matches your example.
>
>     I'm sure Nicolas will have a much more efficient formula, but this
>     would work :)
>
>     - Bert -
>
>
> make it right > make it fast so it sounds like a good starting point :)
> since I see a lot of logic in the complex ASN1 spec, it'll be even
> I see nothing about negative zero, nan seems handled by later version
> if we can trust SO answers.
> In any case, like requested on SO, a good reference test database
> sounds mandatory.
>
> We could also peek what Juan did in Cuis, like:
>
> Float>>exponentPart
>     "Alternative implementation for exponent"
>     ^self partValues: [ :sign :exponent :mantissa | exponent ]
>
> partValues: aThreeArgumentBlock
>     ^ self
>         partValues: aThreeArgumentBlock
>         ifInfinite: [ self error: 'Can not handle infinity' ]
>         ifNaN: [ self error: 'Can not handle Not-a-Number' ].
>
> partValues: aThreeArgumentBlock ifInfinite: aZeroOrOneArgBlock ifNaN:
> otherZeroOrOneOrTwoArgBlock
>     "
>     Float pi hex print
>     Float pi partValues: [ :sign :exponent :mantissa | { sign hex.
> exponent hex. mantissa hex} print ]
>     0.0 partValues: [ :sign :exponent :mantissa | { sign hex. exponent
> hex. mantissa hex} print ]
>     For 0.0, exponent will be the minimum possible, i.e. -1023, and
> mantissa will be 0.
>     "
>     | allBits sign exponent mantissa exponentBits fractionBits |
>
>     " Extract the bits of an IEEE double float "
>     allBits _ ((self basicAt: 1) bitShift: 32) + (self basicAt: 2).
>
>     " Extract the sign and the biased exponent "
>     sign _ (allBits bitShift: -63) = 0 ifTrue: [1] ifFalse: [-1].
>     exponentBits _ (allBits bitShift: -52) bitAnd: 16r7FF.
>
>     " Extract fractional part "
>     fractionBits _ allBits bitAnd: 16r000FFFFFFFFFFFFF.
>
>     " Special cases: infinites and NaN"
>     exponentBits = 16r7FF ifTrue: [
>         ^fractionBits = 0
>             ifTrue: [ aZeroOrOneArgBlock valueWithPossibleArgument: self ]
>             ifFalse: [ otherZeroOrOneOrTwoArgBlock
> valueWithPossibleArgument: self and: fractionBits ]].
>
>     " Unbias exponent: 16r3FF is bias"
>     exponent _ exponentBits - 16r3FF.
>
>     " Replace omitted leading 1 in fraction if appropriate"
>     "If expPart = 0, I am +/-zero or a denormal value. In such cases,
> no implicit leading bit in mantissa"
>     exponentBits = 0
>         ifTrue: [
>             mantissa _ fractionBits.
>             exponent _ exponent + 1 ]
>         ifFalse: [
>             mantissa _ fractionBits bitOr: 16r0010000000000000 ].
>
>     "Evaluate the block"
>     ^aThreeArgumentBlock value: sign value: exponent value: mantissa
>
>
> Otherwise, on a 64 bit VM, i would start with significandAsInteger
> which is a SmallInteger, and play with bitShift: 1 - lowbit...
> But it would need measurements and is probably a bad idea in 32bits.
>
>
>

--