[squeak-dev] ASN.1 Floats

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Thu Oct 12 19:21:22 UTC 2017


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
when reading!
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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20171012/d438bf9a/attachment.html>


More information about the Squeak-dev mailing list