ASN.1 Floats

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

ASN.1 Floats

Bert Freudenberg
On Thu, Oct 12, 2017 at 11:36 AM, Alan Pinch <[hidden email]> 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 -


Reply | Threaded
Open this post in threaded view
|

Re: ASN.1 Floats

Nicolas Cellier


2017-10-12 17:46 GMT+02:00 Bert Freudenberg <[hidden email]>:
On Thu, Oct 12, 2017 at 11:36 AM, Alan Pinch <[hidden email]> 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.



Reply | Threaded
Open this post in threaded view
|

Re: ASN.1 Floats

Alan Pinch

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 <[hidden email]>:
On Thu, Oct 12, 2017 at 11:36 AM, Alan Pinch <[hidden email]> 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.




    

-- 
Thank you for your consideration,
Alan


Reply | Threaded
Open this post in threaded view
|

Re: ASN.1 Floats

Hannes Hirzel
In reply to this post by Nicolas Cellier
On 10/12/17, Nicolas Cellier <[hidden email]> wrote:

> 2017-10-12 17:46 GMT+02:00 Bert Freudenberg <[hidden email]>:
>
>> On Thu, Oct 12, 2017 at 11:36 AM, Alan Pinch <[hidden email]>
>> 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.

Please note the words 'in any case' and '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.
>

Reply | Threaded
Open this post in threaded view
|

Re: ASN.1 Floats

Alan Pinch


On 10/13/2017 07:31 AM, H. Hirzel wrote:

> On 10/12/17, Nicolas Cellier <[hidden email]> wrote:
>> 2017-10-12 17:46 GMT+02:00 Bert Freudenberg <[hidden email]>:
>>
>>> On Thu, Oct 12, 2017 at 11:36 AM, Alan Pinch <[hidden email]>
>>> 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.
> 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.
>>

--
Thank you for your consideration,
Alan


Reply | Threaded
Open this post in threaded view
|

Re: ASN.1 Floats

Alan Pinch
Please see Cryptography for the initial support for ASN1 Reals.


On 10/13/2017 10:08 AM, Alan Pinch wrote:

>
>
> On 10/13/2017 07:31 AM, H. Hirzel wrote:
>> On 10/12/17, Nicolas Cellier <[hidden email]> wrote:
>>> 2017-10-12 17:46 GMT+02:00 Bert Freudenberg <[hidden email]>:
>>>
>>>> On Thu, Oct 12, 2017 at 11:36 AM, Alan Pinch <[hidden email]>
>>>> 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.
>> 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.
>>>
>

--
Thank you for your consideration,
Alan


Reply | Threaded
Open this post in threaded view
|

Re: ASN.1 Floats

Alan Pinch
It encodes Reals, Fractions and Scaled Decimals, I think. It decodes
base-2, and it may decode base-8 and -16, I do not know. No decimal
tests in base-2. I attempted to signal exceptions where appropriate.

On a different topic, I wondered the best examples of a tree of semantic
stored items, looked up from a leaf dictionary up through import and
parent libraries, a TreeBrancher of sorts. Is this an area where common
approach may help multiple aspects?


On 10/14/2017 05:25 PM, Alan Pinch wrote:

> Please see Cryptography for the initial support for ASN1 Reals.
>
>
> On 10/13/2017 10:08 AM, Alan Pinch wrote:
>>
>>
>> On 10/13/2017 07:31 AM, H. Hirzel wrote:
>>> On 10/12/17, Nicolas Cellier <[hidden email]>
>>> wrote:
>>>> 2017-10-12 17:46 GMT+02:00 Bert Freudenberg <[hidden email]>:
>>>>
>>>>> On Thu, Oct 12, 2017 at 11:36 AM, Alan Pinch <[hidden email]>
>>>>> 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.
>>> 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.
>>>>
>>
>

--
Thank you for your consideration,
Alan