module Flt

Flt contains constants for common floating point formats.

Constants

APPLE

Sofware floating point implementatin for the Apple II (6502) the significand & sign are a single field in two's commplement

HFP_DOUBLE
HFP_EXTENDED
HFP_SINGLE
IEEE_128
IEEE_128_BE
IEEE_DEC128
IEEE_DEC32

old names

IEEE_DEC64
IEEE_DOUBLE
IEEE_D_BE
IEEE_EXTENDED
IEEE_HALF
IEEE_H_BE
IEEE_QUAD
IEEE_Q_BE
IEEE_SINGLE
IEEE_S_BE
IEEE_X_BE
IEEE_binaryx

old names

MBF_EXTENDEND
RPL
RPL_X

Public Instance Methods

*(v) click to toggle source
# File lib/float-formats/classes.rb, line 1751
def *(v)
  # TODO: coercion
  if v.form_class==form_class
    form_class.arithmetic do |t|
      x = to(t,:exact) * v.to(t,:exact)
      form_class.from_number(x,:exact)
    end
  else
    # TODO
  end
end
+(v) click to toggle source
# File lib/float-formats/classes.rb, line 1718
def +(v)
  # TODO: coercion
  if v.form_class==form_class
    form_class.arithmetic do |t|
      x = to(t,:exact) + v.to(t,:exact)
      form_class.from_number(x,:exact)
    end
  else
    # TODO
  end
end
-(v) click to toggle source
# File lib/float-formats/classes.rb, line 1740
def -(v)
  # TODO: coercion
  if v.form_class==form_class
    form_class.arithmetic do |t|
      x = to(t,:exact) - v.to(t,:exact)
      form_class.from_number(x,:exact)
    end
  else
    # TODO
  end
end
-@() click to toggle source
# File lib/float-formats/classes.rb, line 1715
def -@
  minus
end
/(v) click to toggle source
# File lib/float-formats/classes.rb, line 1729
def /(v)
  # TODO: coercion
  if v.form_class==form_class
    form_class.arithmetic do |t|
      x = to(t,:exact) / v.to(t,:exact)
      form_class.from_number(x,:exact)
    end
  else
    # TODO
  end
end
bcd2dpd(arg) click to toggle source

Compress BCD to Densely Packed Decimal

adapted from Mike Cowlishaw's Rexx program:

http://www2.hursley.ibm.com/decimal/DPDecimal.html
# File lib/float-formats/bytes.rb, line 338
def bcd2dpd(arg)
  # assign each bit to a variable, named as in the description
  a,b,c,d,e,f,g,h,i,j,k,m = ("%012B"%arg).split('').collect{|bit| bit.to_i}

  # derive the result bits, using boolean expressions only
  #-- [the operators are: '&'=AND, '|'=OR, '\'=NOT.]
  p=b | (a & j) | (a & f & i)
  q=c | (a & k) | (a & g & i)
  r=d
  s=(f & (bitnot(a) | bitnot(i))) | (bitnot(a) & e & j) | (e & i)
  t=g  | (bitnot(a) & e &k) | (a & i)
  u=h
  v=a | e | i
  w=a | (e & i) | (bitnot(e) & j)
  x=e | (a & i) | (bitnot(a) & k)
  y=m

  # concatenate the bits and return
    # result = [p,q,r,s,t,u,v,w,x,y].collect{|bit| bit.to_s}.inject{|aa,bb|aa+bb}.to_i(2)
    result = 0
    [p,q,r,s,t,u,v,w,x,y].each do |bit|
      result <<= 1
      result |= bit
    end
  result
end
bitnot(b) click to toggle source

Negate a bit. Auxiliar method for DPD conversions

# File lib/float-formats/bytes.rb, line 330
def bitnot(b)
  (~b)&1
end
convert_bytes(bytes,from_format,to_format) click to toggle source
# File lib/float-formats/classes.rb, line 1991
def convert_bytes(bytes,from_format,to_format)
  from_format.from_bytes(bytes).convert_to(to_format)
end
dbl_from_float(val, little_endian=true) click to toggle source

generate a DBL value stored in a byte string given a Float value

# File lib/float-formats/native.rb, line 89
def dbl_from_float(val, little_endian=true)
  code = little_endian ? 'E':'G'
  [val].pack(code)
end
dbl_from_text(txt, little_endian=true) click to toggle source

generate a DBL value stored in a byte string given a decimal value formatted as text

# File lib/float-formats/native.rb, line 83
def dbl_from_text(txt, little_endian=true)
  code = little_endian ? 'E':'G'
  [txt].pack(code)
end
dbl_to_float(sgl, little_endian=true) click to toggle source

convert a DBL value stored in a byte string to a Float value

# File lib/float-formats/native.rb, line 95
def dbl_to_float(sgl, little_endian=true)
  code = little_endian ? 'E':'G'
  sgl.unpack(code)[0]
end
define(*arguments) { |cls| ... } click to toggle source
# File lib/float-formats/classes.rb, line 1971
def define(*arguments)
  raise "Invalid number of arguments for Flt definitions." if arguments.size<2 || arguments.size>3
  if arguments.first.kind_of?(Class)
    base,name,parameters = arguments
  elsif arguments[1].kind_of?(Class)
    name,base,parameters = arguments
  else
    name,parameters = arguments
    base = parameters[:base] || FormatBase
  end
  Flt.const_set name, cls=Class.new(base)
  cls.define parameters
  constructor = lambda { |*args| cls.new(*args) }
  Flt.send :define_method,name,constructor
  Flt.send :module_function, name
  yield cls if block_given?
end
dpd2bcd(arg) click to toggle source

Expand Densely Packed Decimal to BCD

adapted from Mike Cowlishaw's Rexx program:

http://www2.hursley.ibm.com/decimal/DPDecimal.html
# File lib/float-formats/bytes.rb, line 369
def dpd2bcd(arg)

  # assign each bit to a variable, named as in the description
  p,q,r,s,t,u,v,w,x,y = ("%010B"%arg).split('').collect{|bit| bit.to_i}

  # derive the result bits, using boolean expressions only
  a= (v & w) & (bitnot(s) | t | bitnot(x))
  b=p & (bitnot(v) | bitnot(w) | (s & bitnot(t) & x))
  c=q & (bitnot(v) | bitnot(w) | (s & bitnot(t) & x))
  d=r
  e=v & ((bitnot(w) & x) | (bitnot(t) & x) | (s & x))
  f=(s & (bitnot(v) | bitnot(x))) | (p & bitnot(s) & t & v & w & x)
  g=(t & (bitnot(v) | bitnot(x))) | (q & bitnot(s) & t & w)
  h=u
  i=v & ((bitnot(w) & bitnot(x)) | (w & x & (s | t)))
  j=(bitnot(v) & w) | (s & v & bitnot(w) & x) | (p & w & (bitnot(x) | (bitnot(s) & bitnot(t))))
  k=(bitnot(v) & x) | (t & bitnot(w) & x) | (q & v & w & (bitnot(x) | (bitnot(s) & bitnot(t))))
  m=y
  # concatenate the bits and return
  # result = [a,b,c,d,e,f,g,h,i,j,k,m].collect{|bit| bit.to_s}.inject{|aa,bb|aa+bb}.to_i(2)
    result = 0
    [a,b,c,d,e,f,g,h,i,j,k,m].each do |bit|
      result <<= 1
      result |= bit
    end
  result
end
dpd_to_hexbcd(dpd, dpd_bits, endianness=:big_endian) click to toggle source

Unpack DPD digits

# File lib/float-formats/bytes.rb, line 430
def dpd_to_hexbcd(dpd, dpd_bits, endianness=:big_endian)

  bcd = ""

  while dpd_bits>=10
    v = dpd2bcd(dpd & 0x3FF)
    dpd >>= 10
    dpd_bits -= 10
    bcd = ("%03X"%v)+bcd
  end

  if dpd_bits>0
    case dpd_bits
      when 4
        v = dpd & 0xF
        n = 1
      when 7
        v = dpd & 0x7F
        n = 2
      else
        raise "Invalid DPD data"
    end
    v = dpd2bcd(v,true)
    bcd = ("%0#{n}X"%v)+bcd
  end

  bcd = bcd.reverse if endianness==:little_endian

  bcd

end
float_bin(x) click to toggle source

binary representation

# File lib/float-formats/native.rb, line 27
def float_bin(x)
  Numerals::Format[:free, :exact_input, :scientific, base: 2].write(x)
end
float_dec(x) click to toggle source

complete exact decimal representation

# File lib/float-formats/native.rb, line 22
def float_dec(x)
  Numerals::Format[:free, :exact_input].write(x)
end
float_from_integral_sign_significand_exponent(sgn,s,e) click to toggle source
# File lib/float-formats/native.rb, line 45
def float_from_integral_sign_significand_exponent(sgn,s,e)
  Float.context.Num(sgn,s,e)
end
float_from_integral_significand_exponent(s,e) click to toggle source

compose float from significand and exponent

# File lib/float-formats/native.rb, line 37
def float_from_integral_significand_exponent(s,e)
  Float.context.Num(s,e)
end
float_shortest_dec(x) click to toggle source

shortest decimal unambiguous reprentation

# File lib/float-formats/native.rb, line 12
def float_shortest_dec(x)
  Numerals::Format[:short].write(x)
end
float_significant_dec(x) click to toggle source

decimal representation showing all significant digits

# File lib/float-formats/native.rb, line 17
def float_significant_dec(x)
  Numerals::Format[:free].write(x)
end
float_to_integral_sign_significand_exponent(x) click to toggle source
# File lib/float-formats/native.rb, line 41
def float_to_integral_sign_significand_exponent(x)
  Float.context.split(x)
end
float_to_integral_significand_exponent(x) click to toggle source

decompose a float into a signed integer significand and exponent (base Float::RADIX)

# File lib/float-formats/native.rb, line 32
def float_to_integral_significand_exponent(x)
  Float.context.to_int_scale(x)
end
hex_from_float(v) click to toggle source

convert a float to C99's hexadecimal notation

# File lib/float-formats/native.rb, line 50
def hex_from_float(v)
  Numerals::Format[:hexbin].write(v)
end
hex_to_float(txt) click to toggle source

convert a string formatted in C99's hexadecimal notation to a float

# File lib/float-formats/native.rb, line 55
def hex_to_float(txt)
  # Numerals::Format[:hexbin].read(txt, type: Float)
  # txt.scanf("%A").first
  Float(txt)
end
hexbcd_to_dpd(bcd, endianness=:big_endian) click to toggle source

Pack a bcd digits string into DPD

# File lib/float-formats/bytes.rb, line 398
def hexbcd_to_dpd(bcd, endianness=:big_endian)

  n = bcd.size
  dpd = 0
  dpd_bits = 0

  i = 0
  m = n%3
  if m>0
    v = bcd2dpd(bcd[0,m].to_i(16))
    i += m
    n -= m
    bits = m==1 ? 4 : 7
    dpd_bits += bits
    dpd <<= bits
    dpd |= v
  end

  while n>0
    v = bcd2dpd(bcd[i,3].to_i(16))
    i += 3
    n -= 3
    bits = 10
    dpd_bits += bits
    dpd <<= bits
    dpd |= v
  end

  [dpd, dpd_bits]
end
sgl_from_float(val, little_endian=true) click to toggle source

generate a SGL value stored in a byte string given a Float value

# File lib/float-formats/native.rb, line 70
def sgl_from_float(val, little_endian=true)
  code = little_endian ? 'e':'g'
  [val].pack(code)
end
sgl_from_text(txt, little_endian=true) click to toggle source

generate a SGL value stored in a byte string given a decimal value formatted as text

# File lib/float-formats/native.rb, line 64
def sgl_from_text(txt, little_endian=true)
  code = little_endian ? 'e':'g'
  [txt].pack(code)
end
sgl_to_float(sgl, littel_endian=true) click to toggle source

convert a SGL value stored in a byte string to a Float value

# File lib/float-formats/native.rb, line 76
def sgl_to_float(sgl, littel_endian=true)
  code = little_endian ? 'e':'g'
  sgl.unpack(code)[0]
end