'
' Number.SetBits
'
' 24 Jan 2002
'
' A number in Avenue is a double precision IEEE float.  In general,
' floats have a mantissa and an exponent, each with a separate sign
' bit.  If the float has n bits (n=64 for double precision) and
' the mantissa has m bits (m=51 for double precision), then the
' exponent has n-m-2 bits.  The float's value is equal to
'
'   mantissa * 2^(exponent-m)
'
' All but the very smallest floats are normalized to make the leading
' digit of the mantissa equal to 1.  (This cannot be done for a value
' of zero, of course.)
'
' Bit offsets in this subroutine begin at 0.  Thus, usually the 0th
' bit of the mantissa is 1.
'===================================================================='

x = SELF.Get(0)        ' Original number
nBits = SELF.Get(4)    ' Number of bits to set; 0 or greater
if (nBits<=0) then
  return x
end
iX = SELF.Get(1)       ' Start bit offset in x; must be 1 or greater
bmpIn = SELF.Get(2)    ' Bitmap
iB = SELF.Get(3)       ' Start bit offset in bmpIn
'
' Deal with negative values by removing the sign bit temporarily.
'

bNegative = (x<0.0)
x = x.Abs
'
' Find the exponent.  We must have
'
'   1/2 <= mantissa*2^-m < 1
' and
'   x = mantissa * 2^(exponent-m)
'
' Therefore
'   1/2 <= x * 2^(m-exponent) < 1
' or
'   2^(exponent-m-1) <= x < 2^(exponent-m)
'
' implying
'   exponent-m-1 <= x.Log(2) < exponent-m
'
' Unfortunately, x.Log(2) could be inaccurately computed.
'
' The term "exponent-m" will be held in the nExponent variable.
'

if (x=0.0) then
  nExponent = -1023 ' ???
else
  '
  ' Exponents must not overflow the range -1023..1024 in
  ' any of the subsequent operations, so that expressions
  ' like 2^(-nExponent) and 2^(nExponent-1) will not overflow.
  '

  nExponent = x.Log(2).Ceiling max -1023
  while (2^(nExponent-1)>x and (nExponent>-1023))
    nExponent = nExponent-1
  end
  while (2^nExponent<=x and (nExponent<1024))
    nExponent = nExponent+1
  end
end
'
' Retain just the mantissa in x:
'

x = 2^(-nExponent)*x
'
' Analyze the mantissa into three parts:
' the "prefix" that precedes the bits to set,
' the "message" that contains the bits to set,
' and the "postfix" that remains.
'
' Bite off the left iX bits of x, then shift another
' nBits left to make room for xMessage:
'

xPrefix = (2^iX*x).Floor
xPrefix = 2^nBits*xPrefix
'
' Bit off the right iX+nBits bits and normalize:
'

xPostfix = 2^(iX+nBits)*x
xPostfix = xPostfix-xPostfix.Floor
'
' Set the "message" bits:
'

xMessage = 0    ' Output bits
if (bmpIn<>NIL) then
  for each iBit in iB..(iB+nBits-1)
  '
  ' Read the next incoming bit.
  '

    b = bmpIn.Get(iBit)
    '
    ' Set the next bit of the message to b.
    '

    xMessage = xMessage*2
    if (b) then
      xMessage = xMessage+1
    end
  end
end
'
' Synthesize the output from the prefix, message, and postfix
' then shift back into normal position and restore the sign bit:
'

x = 2^(nExponent-iX-nBits)*(xPrefix+xMessage+xPostfix)
if (bNegative) then
  x = -x
end
return x
' end of script