## [squeak-dev] ASN.1 Floats

Alan Pinch alan.c.pinch at gmail.com
Fri Oct 13 14:08:16 UTC 2017

```
On 10/13/2017 07:31 AM, H. Hirzel wrote:
> On 10/12/17, Nicolas Cellier <nicolas.cellier.aka.nice at gmail.com> wrote:
>> 2017-10-12 17:46 GMT+02:00 Bert Freudenberg <bert at freudenbergs.de>:
>>
>>> On Thu, Oct 12, 2017 at 11:36 AM, Alan Pinch <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 worse
>> I see nothing about negative zero, nan seems handled by later version if we
>> In any case, like requested on SO, a good reference test database sounds
>> mandatory.
> Please note the words 'in any case' and 'mandatory'   :-)

Indeed. I am struggling a little with writing an unsigned mantissa and a
twos-compliment exponent, ATM. :) I analyzed the first octet to get
base, sign, scaling factor and number of exponent octets, then made
calls to specialized encode methods for each...just evolving protocol to
getting it right, for the moment. Reading is more complex with
additional bases and encodings...I have not analyzed past base-2 so far.

>> 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.
>>

--