[Vm-dev] Potential issue of primitiveTimesTwoPower in Spur 64
Nicolas Cellier
nicolas.cellier.aka.nice at gmail.com
Thu Feb 12 02:27:46 UTC 2015
2015-02-12 3:02 GMT+01:00 Eliot Miranda <eliot.miranda at gmail.com>:
>
> 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?
>
I was focused on image side fallback code and came up to more or less the
same
So it sounds very good to me :)
We still have a compiler warning for long -> int,.
For sure, we can ignore it this time...
But this kind of false warning is pesky.
The risk is to drown a true positive into a flow of false ones...
Using an argument > 2^31 is more theoretical than practicle. It should be
very rare.
So once we have image side for handling this rare case, I wonder if it is
really necessary to complexify the primitive...
And it's good anyway to have a fallback code, it makes the primitives
optional and lower the barrier for guys doing experiments like Bert.
So I would say let the primitive fail, and eliminate the warning.
> 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/20150212/1b891f30/attachment-0001.htm
More information about the Vm-dev
mailing list