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 - |
2017-10-12 17:46 GMT+02:00 Bert Freudenberg <[hidden email]>:
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. |
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:
-- Thank you for your consideration, Alan |
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. > |
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 |
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 |
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 |
Free forum by Nabble | Edit this page |