class Flt::DoubleFormat

Class to define formats such as “double double” by pairing two floating-point values which define a higher precision value by its sum. The :half parameter is a format class that defines the type of each part of the numbers. The formats defined here have a fixed precision, although these formats can actually have a variable precision. For binary formats there's an option to gain one bit of precision by adjusting the sign of the second number. This is enabled by the :extra_prec option. For example, the “double double” format used in PowerPC is this

Flt.define :DoubleDouble, DoubleFormat, half: IEEE_binary64, extra_prec: true

Although this has a fixed 107 bits precision, the format as used in the PowerPC can have greater precision for specific values (by having greater separation between the exponents of both halves)

Public Class Methods

define(params) click to toggle source
Calls superclass method Flt::FormatBase::define
# File lib/float-formats/classes.rb, line 1799
def self.define(params)
  @half = params[:half]
  params = @half.parameters.merge(params)
  if @half.radix==2
    @extra_prec = params[:extra_prec]
  else
    @extra_prec = false
  end
  params[:significand_digits] = 2*@half.significand_digits
  params[:significand_digits] += 1 if @extra_prec
  @significand_digits = params[:significand_digits]

  @hidden_bit = params[:hidden_bit] = @half.hidden_bit

  fields1 = []
  fields2 = []
  params[:fields].each_slice(2) do |s,v|
    fields1 << s # (s.to_s+"_1").to_sym
    fields1 << v
    fields2 << (s.to_s+"_2").to_sym
    fields2 << v
  end
  params[:fields] = fields1 + fields2

  define_fields params[:fields]

  super params
end
half() click to toggle source
# File lib/float-formats/classes.rb, line 1832
def self.half
  @half
end
join_halfs(h1,h2) click to toggle source
# File lib/float-formats/classes.rb, line 1871
def self.join_halfs(h1,h2)
  self.from_bytes(h1.to_bytes+h2.to_bytes)
end
pack(s,m,e) click to toggle source
# File lib/float-formats/classes.rb, line 1851
def self.pack(s,m,e)
  if e.kind_of?(Symbol)
    f1 = @half.pack(s,m,e)
    f2 = @half.pack(+1,0,:zero)
  else
    s1,m1,e1,s2,m2,e2 = split_fp(s,m,e)
    f1 = @half.pack(s1,m1,e1)
    f2 = @half.pack(s2,m2,e2)
  end
  f1+f2
end
radix() click to toggle source
# File lib/float-formats/classes.rb, line 1828
def self.radix
  @half.radix
end
total_bits() click to toggle source
# File lib/float-formats/classes.rb, line 1881
def self.total_bits
  8*total_bytes
end
total_bytes() click to toggle source
# File lib/float-formats/classes.rb, line 1878
def self.total_bytes
  2*@half.total_bytes
end
total_nibbles() click to toggle source
# File lib/float-formats/classes.rb, line 1875
def self.total_nibbles
  2*total_bytes
end
unpack(v) click to toggle source
# File lib/float-formats/classes.rb, line 1836
def self.unpack(v)
  sz = @half.total_bytes
  v1 = @half.unpack(v[0...sz])
  v2 = @half.unpack(v[sz..-1])
  if v1.last == :nan
    nan
  elsif v1.last == :infinity
    infinity(v1.sign)
  else
    v2 = @half.zero.split if @half.new(*v1).subnormal?
    params = v1 + v2
    join_fp(*params)
  end
end

Private Class Methods

split_fp(s,m,e) click to toggle source
# File lib/float-formats/classes.rb, line 1886
def self.split_fp(s,m,e)
  n = @half.significand_digits
  if @half.radix==2
    if @extra_prec
      if (m & (1<<n))==0 # m.to_bits[n] == 0
        m1 = m >> (n+1) # m/2**(n+1)
        e1 = e + n + 1
        s1 = s
        m2 = m & ((1<<n) - 1) # m%2**n
        e2 = e
        s2 = s
      else
        m1 = (m >> (n+1)) + 1 # m/2**(n+1) + 1
        e1 = e + n + 1
        s1 = s
        if m1>=(1<<n) # 2**n
          m1 >>= 1
          e1 += 1
        end
        if m2==0
          m2 = (1<<(n-1)) # 2**(n-1)
          e2 = e+1
          s2 = -s
        else
          m2 = -((m & ((1<<n) - 1)) - (1<<n)) # m%2**n - 2**n
          e2 = e
          s2 = -s
        end
      end
    else # m has 2*n bits
      m1 = m >> n
      e1 = e + n
      s1 = s
      m2 = m & ((1<<n) - 1) # m%2**n
      e2 = e
      s2 = s
    end
  else
      m1 = m / @half.radix_power(n)
      e1 = e + n
      s1 = s
      m2 = m % @half.radix_power(n)
      e2 = e
      s2 = s
  end
  [s1,m1,e1,s2,m2,e2]
end

Public Instance Methods

split_halfs() click to toggle source
# File lib/float-formats/classes.rb, line 1863
def split_halfs
  b = to_bytes
  sz = form_class.half.total_bytes
  b1 = b[0...sz]
  b2 = b[sz..-1]
  [form_class.half.from_bytes(b1), form_class.half.from_bytes(b2)]
end