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

Eliot Miranda eliot.miranda at gmail.com
Thu Feb 12 01:43:20 UTC 2015


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20150211/eabb0098/attachment-0001.htm


More information about the Vm-dev mailing list