[Vm-dev] Potential issue of primitiveTimesTwoPower in Spur 64

Eliot Miranda eliot.miranda at gmail.com
Thu Feb 12 02:02:54 UTC 2015


Again not close enough.  If value < 0, then result is < 0, so

primitiveTimesTwoPower
<option: #Spur64BitMemoryManager>
| rcvr result arg twiceMaxExponent |
<var: #rcvr type: #double>
<var: #result type: #double>
arg := self stackTop.
(objectMemory isIntegerObject: arg) ifFalse:
[^self primitiveFailFor: PrimErrBadArgument].
rcvr := objectMemory floatValueOf: (self stackValue: 1).
((self isFinite: rcvr) and: [rcvr ~= 0])
ifFalse:
[result := rcvr]
ifTrue:
[arg := objectMemory integerValueOf: arg.
 twiceMaxExponent := 2 * (1 << self floatExponentBits).
 arg < twiceMaxExponent negated
ifTrue:
[result := rcvr < 0.0 ifTrue: [-0.0] ifFalse: [0.0]]
ifFalse:
[arg > twiceMaxExponent
ifTrue:
[result := rcvr < 0.0 ifTrue: [-1.0e200 / 10.e-200] ifFalse: 1.0e200 /
1.0e-200]]
ifFalse:
[result := self cCode: [self ld: rcvr exp: arg]
inSmalltalk: [rcvr timesTwoPower: arg]]]].
self pop: 2 thenPushFloat: result

Right?

On Wed, Feb 11, 2015 at 5:57 PM, Eliot Miranda <eliot.miranda at gmail.com>
wrote:

> Hmm, close, but I need to check explicitly for zero.  Here's the version
> for the FloatMathPlugin (& with more conventional formatting :-) ):
>
> primitiveTimesTwoPower
> "Computes E raised to the receiver power."
> | rcvr arg twiceMaxExponent result |
> <export: true>
> <var: #rcvr type: #double>
> <var: #result type: #double>
> arg := interpreterProxy stackIntegerValue: 0.
> rcvr := interpreterProxy stackFloatValue: 1.
> (interpreterProxy failed) ifTrue:
> [^nil].
> ((self isFinite: rcvr) and: [rcvr ~= 0.0])
> ifFalse:
> [result := rcvr]
> ifTrue:
> [twiceMaxExponent := 2 * (1 << 11).
>  arg < twiceMaxExponent negated
> ifTrue:
> [result := 0.0]
> ifFalse:
> [arg > twiceMaxExponent
> ifTrue:
> [result := 1.0e200 / 1.0e-200]
> ifFalse:
> [result := self cCode: '__ieee754_ldexp(rcvr, arg)'
> inSmalltalk: [rcvr timesTwoPower: arg]]]].
> (self isnan: result) ifTrue:
> [^interpreterProxy primitiveFail].
> interpreterProxy
> pop: interpreterProxy methodArgumentCount + 1;
> pushFloat: result
>
> On Wed, Feb 11, 2015 at 5:43 PM, Eliot Miranda <eliot.miranda at gmail.com>
> wrote:
>
>> and of course I meant
>>
>> primitiveTimesTwoPower
>> | rcvr result arg twiceMaxExponent |
>> <var: #rcvr type: #double>
>> <var: #result type: #double>
>> arg := self stackTop.
>> (objectMemory isIntegerObject: arg) ifFalse:
>> [^self primitiveFailFor: PrimErrBadArgument].
>> rcvr := objectMemory floatValueOf: (self stackValue: 1).
>> (self isFinite: rcvr) ifFalse:
>> [result := rcvr] ifTrue:
>> [arg := objectMemory integerValueOf: arg.
>>  twiceMaxExponent := 2 * (1 << self floatExponentBits).
>>  arg < twiceMaxExponent negated ifTrue:
>> [result := 0.0] ifFalse:
>> [arg > twiceMaxExponent ifTrue:
>> [result := 1.0e200 / 1.0e-200] ifFalse:
>> [result := self cCode: [self ld: rcvr exp: arg]
>> inSmalltalk: [rcvr timesTwoPower: arg]]]].
>> self pop: 2 thenPushFloat: result
>>
>> On Wed, Feb 11, 2015 at 5:41 PM, Eliot Miranda <eliot.miranda at gmail.com>
>> wrote:
>>
>>> Hi Nicolas,
>>>
>>> On Wed, Feb 11, 2015 at 2:57 PM, Nicolas Cellier <
>>> nicolas.cellier.aka.nice at gmail.com> wrote:
>>>
>>>>
>>>> Some C functions in libm only take an int, not a long.
>>>> In 32 bits int=long, so no problem.
>>>> In 64 bits generally int=32 bits, long=64 bits, so casting a long to
>>>> int might lead to catastrophic loss and unexpected behavior.
>>>>
>>>> This is the case for example in primitiveTimesTwoPower
>>>>     | rcvr arg |
>>>>     <var: #rcvr type: #double>
>>>>     arg := self popInteger.
>>>>     rcvr := self popFloat.
>>>>     self successful
>>>>         ifTrue: [ self pushFloat: (self cCode: 'ldexp(rcvr, arg)'
>>>> inSmalltalk: [rcvr timesTwoPower: arg]) ]
>>>>         ifFalse: [ self unPop: 2 ]
>>>>
>>>> arg will be a long in Spur64, won't it?
>>>> but ldexp only takes an int
>>>>     double ldexp(double x, int exp);.
>>>>
>>>> So guess what if we call (1.0 timesTwoPower: 16r10000000001)...
>>>> Normally there should be a C compiler warning, and we should care of it.
>>>>
>>>> To solve this, maybe we need a
>>>>
>>>>     <var: #arg type: #int>
>>>>     arg := self signed32BitValueOf: stackTop.
>>>>
>>>
>>>
>>> I think we can check intelligently.  We know that for a finite non-zero
>>> value,  ldexp(value, n) is infinite if n > (2 * max exponent) and zero if n
>>> < (2 * max exponent), that for a NaN value, ldexp(value, n) is NaN and for
>>> an infinite value ldexp(value,n) is infinite, and for a 0 value, it is
>>> zero.  So I propose
>>>
>>> primitiveTimesTwoPower
>>> | rcvr result arg twiceMaxExponent |
>>> <var: #rcvr type: #double>
>>> <var: #result type: #double>
>>> arg := self stackTop.
>>> (objectMemory isIntegerObject: arg) ifFalse:
>>> [^self primitiveFailFor: PrimErrBadArgument].
>>> rcvr := objectMemory floatValueOf: (self stackValue: 1).
>>> (self isFinite: rcvr) ifFalse:
>>> [result := rcvr] ifTrue:
>>> [arg := objectMemory integerValueOf: arg.
>>>  twiceMaxExponent := 2 * (1 << self floatExponentBits).
>>>  arg < twiceMaxExponent ifTrue:
>>> [result := 0.0] ifFalse:
>>> [arg > twiceMaxExponent ifTrue:
>>> [result := 1.0e200 / 1.0e-200] ifFalse:
>>> [result := self cCode: [self ld: rcvr exp: arg]
>>> inSmalltalk: [rcvr timesTwoPower: arg]]]].
>>> self pop: 2 thenPushFloat: result
>>> --
>>> best,
>>> Eliot
>>>
>>
>>
>>
>> --
>> best,
>> Eliot
>>
>
>
>
> --
> best,
> Eliot
>



-- 
best,
Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20150211/cae3a095/attachment-0001.htm


More information about the Vm-dev mailing list